import {
  Controller,
  Post,
  Body,
  HttpException,
  HttpStatus,
  Req,
} from '@nestjs/common';
import { Request } from 'express';
import { ApiTags, ApiOperation, ApiBody, ApiResponse } from '@nestjs/swagger';
import { UserService } from '../../modules/user/user.service';
import { Public } from '../../modules/auth/public.decorator';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { UserSessionEntity } from '../../modules/user_sessions/entities/user_session.entity';
import * as crypto from 'crypto';
import { MobileOnboardingStateService } from '../onboarding/mobile-onboarding-state.service';
import { JwtService } from '@nestjs/jwt';
import { v4 as uuidv4 } from 'uuid';

@ApiTags('Mobile_Auth')
@Controller('mobile/auth')
export class MobileAuthController {
  constructor(
    private readonly userService: UserService,
    private readonly mobileOnboardingStateService: MobileOnboardingStateService,
    @InjectRepository(UserSessionEntity)
    private readonly sessionRepo: Repository<UserSessionEntity>,
    private readonly jwtService: JwtService,
  ) {}

  @Public()
  @Post('start')
  @ApiOperation({
    summary: 'Smart Auth Start - Role Aware',
    description:
      'Initiates authentication flow for mobile app. Supports both seeker and recruiter roles.',
  })
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        phone: {
          type: 'string',
          example: '9988776655',
          description: 'User phone number',
        },
        role: {
          type: 'string',
          enum: ['seeker', 'recruiter'],
          example: 'seeker',
          description: 'User role',
        },
        source: {
          type: 'string',
          enum: ['android', 'ios'],
          example: 'android',
          description: 'Onboarding source',
        },
      },
      required: ['phone', 'role'],
    },
  })
  async smartAuthStart(
    @Body()
    body: {
      phone: string;
      role: 'seeker' | 'recruiter';
      source?: 'android' | 'ios';
    },
  ) {
    const { phone, role } = body;

    if (!phone || !role) {
      throw new HttpException(
        'Phone and role are required',
        HttpStatus.BAD_REQUEST,
      );
    }

    if (role !== 'seeker' && role !== 'recruiter') {
      throw new HttpException('Invalid role', HttpStatus.BAD_REQUEST);
    }

    try {
      const phoneCheck = await this.userService.checkPhoneExists(phone, role);
      let flow: 'registration' | 'login' | 'reactivation';

      if (!phoneCheck.exists && !phoneCheck.hasInactiveAccounts) {
        // ── NEW USER: No account at all → Registration flow
        await this.userService.sendRegistrationOTP(phone, role);
        flow = 'registration';
        return {
          success: true,
          flow,
          role,
          message: 'OTP sent successfully',
        };
      }

      if (phoneCheck.hasInactiveAccounts) {
        // ── INACTIVE USER: Account exists but is deactivated → Reactivation flow
        const result = await this.userService.sendReactivationOTP(phone, role);
        flow = 'reactivation';
        return {
          success: true,
          flow,
          role,
          message: 'Your account is inactive. OTP sent for reactivation.',
          hasEmail: result.hasEmail, // mobile can show "Also send to email" option
        };
      }

      // ── ACTIVE USER: Normal login flow
      await this.userService.sendOTPForRole(phone, role);
      flow = 'login';

      return {
        success: true,
        flow,
        role,
        message: 'OTP sent successfully',
      };
    } catch (error: any) {
      throw new HttpException(error.message, HttpStatus.BAD_REQUEST);
    }
  }

  @Public()
  @Post('handshake')
  @ApiOperation({ summary: 'Handshake: exchange mobile sessionToken for JWTs' })
  async handshake(
    @Req() req: Request,
    @Body() body: { sessionToken?: string },
  ) {
    try {
      const { sessionToken } = body;

      if (!sessionToken || typeof sessionToken !== 'string') {
        throw new HttpException(
          'sessionToken is required',
          HttpStatus.BAD_REQUEST,
        );
      }

      const session = await this.sessionRepo.findOne({
        where: { sessionToken, isActive: 1 },
      });

      if (!session) {
        throw new HttpException(
          'Invalid or expired sessionToken',
          HttpStatus.UNAUTHORIZED,
        );
      }

      const user = await this.userService.findOne(session.userId);
      if (!user) {
        throw new HttpException(
          'User not found for session',
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }

      const sessionId = uuidv4();
      (req.session as any).sessionIndex = sessionId;

      const payload = {
        username: user.email || user.phone,
        sub: user.id,
        sessionId: sessionId,
        ip: req.ip,
        host: (req as any).hostname,
        activeRole: user.role,
      };

      const access_token = this.jwtService.sign(payload, { expiresIn: '24h' });
      const refresh_token = this.jwtService.sign(payload, { expiresIn: '24h' });

      let redirect = '';
      if (user.role === 'seeker') {
        redirect =
          user.onboardingStatus === 'in_progress'
            ? '/seeker/onboarding'
            : '/seeker/dashboard';
      } else if (user.role === 'recruiter') {
        redirect =
          user.onboardingStatus === 'in_progress'
            ? '/recruiter/onboarding'
            : '/recruiter/dashboard';
      }

      return {
        success: true,
        user: {
          id: user.id,
          phone: user.phone,
          role: user.role,
          fullName: user.fullName || null,
          onboarding_status: user.onboardingStatus || null,
          onboarding_step: user.onboardingStep ?? null,
          selected_role_category: user.selectedRoleCategory || null,
        },
        access_token,
        refresh_token,
        redirect,
      };
    } catch (error: any) {
      throw new HttpException(error.message, HttpStatus.BAD_REQUEST);
    }
  }

  @Public()
  @Post('verify')
  @ApiOperation({
    summary: 'Smart Auth Verify - OTP Verification',
    description:
      'Verifies OTP for both registration and login flows. Returns user data and redirect path.',
  })
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        phone: {
          type: 'string',
          example: '9988776655',
          description: 'User phone number',
        },
        otp: {
          type: 'string',
          example: '1234',
          description: '4-digit OTP code',
        },
        role: {
          type: 'string',
          enum: ['seeker', 'recruiter'],
          example: 'seeker',
          description: 'User role',
        },
        source: {
          type: 'string',
          enum: ['android', 'ios'],
          example: 'android',
          description: 'Onboarding source',
        },
        firebaseToken: {
          type: 'string',
          example: 'FIREBASE_TOKEN_HERE',
          description: 'Firebase push notification token',
        },
      },
      required: ['phone', 'otp', 'role'],
    },
  })
  async smartAuthVerify(
    @Req() req: Request,
    @Body()
    body: {
      phone: string;
      otp: string;
      role: 'seeker' | 'recruiter';
      source?: 'android' | 'ios';
      firebaseToken?: string;
    },
  ) {
    const { phone, otp, role, source, firebaseToken } = body;

    if (!phone || !otp || !role) {
      throw new HttpException(
        'Phone, OTP and role are required',
        HttpStatus.BAD_REQUEST,
      );
    }

    if (role !== 'seeker' && role !== 'recruiter') {
      throw new HttpException('Invalid role', HttpStatus.BAD_REQUEST);
    }

    // Extract deviceType from User-Agent and map to DB Enum: ['android', 'ios', 'tablet', 'web']
    const ua = req.headers['user-agent'] || '';
    let mappedDeviceType: 'android' | 'ios' | 'tablet' | 'web' = 'web';

    if (/tablet|ipad/i.test(ua)) {
      mappedDeviceType = 'tablet';
    } else if (/mobile/i.test(ua)) {
      mappedDeviceType = /iPhone|iPod/i.test(ua) ? 'ios' : 'android';
    }

    const finalDeviceType = source || mappedDeviceType;

    // console.log(`[AuthDebug] UA: ${ua}`);
    // console.log(`[AuthDebug] Source: ${source}`);
    // console.log(`[AuthDebug] Final DeviceType: ${finalDeviceType}`);

    try {
      const phoneCheck = await this.userService.checkPhoneExists(phone, role);
      let user;

      if (!phoneCheck.exists && !phoneCheck.hasInactiveAccounts) {
        // ── NEW USER: verify registration OTP
        const verified = await this.userService.verifyRegistrationOTP(
          phone,
          otp,
          role,
          source || 'web',
          finalDeviceType,
        );
        if (!verified) {
          throw new HttpException(
            'Invalid or expired OTP',
            HttpStatus.BAD_REQUEST,
          );
        }
        // Fetch user after verification (created inside verifyRegistrationOTP)
        user = await this.userService.findByPhoneAndRole(phone, role);
      } else if (phoneCheck.hasInactiveAccounts) {
        // ── INACTIVE USER: verify reactivation OTP → activates account
        const verified = await this.userService.verifyReactivationOTP(
          phone,
          otp,
          role,
        );
        if (!verified) {
          throw new HttpException(
            'Invalid or expired OTP',
            HttpStatus.BAD_REQUEST,
          );
        }
        // Fetch the now-active user
        user = await this.userService.findByPhoneAndRole(phone, role);
        if (!user || user.status !== 'active') {
          throw new HttpException(
            'Account could not be reactivated. Please contact support.',
            HttpStatus.INTERNAL_SERVER_ERROR,
          );
        }
      } else {
        // ── ACTIVE USER: verify login OTP
        user = await this.userService.loginWithOTPAndRole(phone, otp, role);
        if (!user) {
          throw new HttpException(
            'Invalid or expired OTP',
            HttpStatus.BAD_REQUEST,
          );
        }

        // Initialize mobile onboarding step if moving from Web to Mobile.
        // Step 0 means all mobile steps are done and only /complete remains.
        if (
          user.onboardingStatus === 'in_progress' &&
          user.mobileOnboardingStep === null
        ) {
          const onboardingData = await this.userService.getOnboardingData(
            user.id,
          );
          const nextMobileStep =
            this.mobileOnboardingStateService.isReadyToComplete(
              user,
              onboardingData,
            )
              ? 0
              : 1;

          await this.userService.update(user.id, {
            mobileOnboardingStep: nextMobileStep,
          });
          user.mobileOnboardingStep = nextMobileStep;
        }
      }

      if (!user) {
        throw new HttpException(
          'User not found after verification',
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }

      // Dynamic redirect rules
      let redirect = '';
      if (role === 'seeker') {
        redirect =
          user.onboardingStatus === 'in_progress'
            ? '/seeker/onboarding'
            : '/seeker/dashboard';
      } else if (role === 'recruiter') {
        redirect =
          user.onboardingStatus === 'in_progress'
            ? '/recruiter/onboarding'
            : '/recruiter/dashboard';
      }

      // Generate a unique URL-safe Session Token for mobile clients.
      const sessionToken = crypto
        .randomBytes(32)
        .toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=+$/g, '');

      // Save Session to Database
      await this.sessionRepo.save({
        userId: user.id,
        sessionToken: sessionToken,
        deviceType: finalDeviceType,
        firebaseToken: firebaseToken,
        isActive: 1,
      });

      const response = {
        success: true,
        message: 'OTP Verified successfully',
        sessionToken: sessionToken,
        user: {
          id: user.id,
          phone: user.phone,
          role: user.role,
          fullName: user.fullName || null,
          onboarding_status: user.onboardingStatus || null,
          onboarding_step: user.onboardingStep ?? null,
          mobile_onboarding_step:
            user.mobileOnboardingStep === 0
              ? null
              : (user.mobileOnboardingStep ?? null),
          ready_to_complete: user.mobileOnboardingStep === 0,
          selected_role_category: user.selectedRoleCategory || null,
        },
        redirect: redirect || '',
      };
      console.log(
        '[AuthDebug] Final Response:',
        JSON.stringify(response, null, 2),
      );
      return response;
    } catch (error: any) {
      throw new HttpException(error.message, HttpStatus.BAD_REQUEST);
    }
  }
}
