import type { Request, Response, NextFunction } from 'express';
import { firebaseAuth } from '../config/firebase.js';
import * as authModel from '../models/auth.model.js';
import logger from '../config/logger.js';
import { errorResponse, tenantSuspendedResponse } from '../utils/response.js';
import { isOrganizationSuspended } from '../utils/organizationStatus.js';

export interface AuthUser {
  sub: string;
  firebaseUid: string;
  role: string;
  // Null until an admin assigns the user to one (PATCH /users/:id/organization).
  // No route filters by this yet — see the note on User.organizationId in
  // prisma/schema.prisma for what's actually scoped vs not.
  organizationId: number | null;
}

// Verifies the Firebase ID token from the client SDK, then finds (or,
// on a user's very first request, creates) the matching local `User` row —
// Firebase owns credentials, this table only holds our own app data (role, etc).
export default async function verifyFirebaseToken(req: Request, res: Response, next: NextFunction) {
  const header = req.headers.authorization;
  if (!header?.startsWith('Bearer ')) {
    return void errorResponse(res, 'Authentication required', 401);
  }

  const idToken = header.slice('Bearer '.length);
  let decoded;
  try {
    decoded = await firebaseAuth.verifyIdToken(idToken);
  } catch {
    return void errorResponse(res, 'Invalid or expired token', 401);
  }

  try {
    let user = await authModel.findUserByFirebaseUid(decoded.uid);
    if (!user) {
      user = await authModel.createFirebaseUser({
        firebaseUid: decoded.uid,
        email: decoded.email ?? '',
        name: (decoded.name as string | undefined) ?? decoded.email ?? 'User',
        avatarUrl: (decoded.picture as string | undefined) ?? null,
        emailVerified: decoded.email_verified ?? false,
      });
    } else {
      // Fire-and-forget: don't hold up the request on a timestamp update.
      authModel.touchLastLogin(user.id).catch((error: unknown) => {
        logger.error('Failed to update last_login_at', { message: error instanceof Error ? error.message : String(error) });
      });
    }

    if (!user.isActive) return void errorResponse(res, 'This account has been deactivated', 403);
    // A suspended organization is blocked on every request, not only at login.
    if (user.organization && isOrganizationSuspended(user.organization)) {
      return void tenantSuspendedResponse(res, user.organization.name);
    }

    // A user reaching here just verified a Firebase ID token, so firebaseUid is
    // always set — nullable only for the tenant-invite flow's not-yet-accepted rows.
    req.user = { sub: String(user.id), firebaseUid: user.firebaseUid!, role: user.role?.name ?? 'user', organizationId: user.organizationId };
    next();
  } catch (error) {
    next(error);
  }
}
