import {
  Controller,
  Post,
  Get,
  Body,
  Param,
  Query,
  Req,
  HttpCode,
  UseGuards,
  BadRequestException,
} from '@nestjs/common';
import type { Request } from 'express';
import { Logger } from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';

import { ClientPortalService } from './services/client-portal.service';
import { ClientAuthService } from './services/client-auth.service';
import { JwtAuthGuard } from './../auth/guards/jwt-auth.guard';
import {
  InviteClientDto,
  ClientLoginDto,
  VerifyOtpDto,
  ListClientAuditsDto,
  ResendOtpDto,
} from './dto/client-portal.dto';
import { Public } from '../common/guards/decorators/public.decorator';
import { getErrorMessage } from '../common/utils/error.helper';
import { CompanyClientLink } from '../companies/entities/company-client-link.entity';


@Controller('client-portal')
export class ClientPortalController {
  private readonly logger = new Logger('ClientPortalController');

  constructor(
    private readonly clientPortalService: ClientPortalService,
    private readonly clientAuthService: ClientAuthService,

    @InjectRepository(CompanyClientLink, 'scheme_dbs')
    private readonly companyClientLinkRepository: Repository<CompanyClientLink>,
  ) { }

  /**
   * ═════════════════════════════════════════════════════════
   * AUTHENTICATION ENDPOINTS (Public)
   * ═════════════════════════════════════════════════════════
   */

  /**
   * Invite client to portal
   * @param inviteDto Company ID, email, phone
   * @param req Request object to get user ID
   */
  @Post('invite')
  @UseGuards(JwtAuthGuard)
  @HttpCode(200)
  async inviteClient(
    @Body() inviteDto: InviteClientDto,
    @Req() req: Request,
  ): Promise<any> {
    this.logger.log(`POST /client-portal/invite`);

    try {
      const userId = this.getCurrentUserId(req);
      const result = await this.clientAuthService.inviteClient(
        inviteDto.company_id,
        inviteDto.client_email,
        inviteDto.client_phone || '',
        userId,
      );
      return { success: true, data: result };
    } catch (error) {
      // ✅ FIX: Use error helper
      this.logger.error(
        `❌ Invite failed: ${getErrorMessage(error)}`,
      );
      throw error;
    }
  }

  /**
   * Client login - verify invite token and send OTP
   * @param loginDto Email and invite token
   */
  @Post('login')
  @Public()
  @HttpCode(200)
  async clientLogin(@Body() loginDto: ClientLoginDto): Promise<any> {
    this.logger.log(`POST /client-portal/login`);

    try {
      const result = await this.clientAuthService.clientLogin(
        loginDto.email || '',
        loginDto.token || '',
      );
      return { success: true, data: result };
    } catch (error) {
      // ✅ FIX: Use error helper
      this.logger.error(
        `❌ Login failed: ${getErrorMessage(error)}`,
      );
      throw error;
    }
  }

  /**
   * Verify OTP and get JWT token
   * @param verifyDto Email and OTP code
   */
  @Post('verify-otp')
  @Public()
  @HttpCode(200)
  async verifyOtp(@Body() verifyDto: VerifyOtpDto): Promise<any> {
    this.logger.log(`POST /client-portal/verify-otp`);

    try {
      const result = await this.clientAuthService.verifyOtp(
        verifyDto.email,
        verifyDto.otp_code,
      );
      return { success: true, data: result };
    } catch (error) {
      // ✅ FIX: Use error helper
      this.logger.error(
        `❌ OTP verification failed: ${getErrorMessage(error)}`,
      );
      throw error;
    }
  }

  /**
   * Resend OTP code
   * @param resendDto Email and invite token
   */
  @Post('resend-otp')
  @Public()
  @HttpCode(200)
  async resendOtp(@Body() resendDto: ResendOtpDto): Promise<any> {
    this.logger.log(`POST /client-portal/resend-otp`);

    try {
      const result = await this.clientAuthService.resendOtp(
        resendDto.email,
        resendDto.token,
      );
      return { success: true, data: result };
    } catch (error) {
      // ✅ FIX: Use error helper
      this.logger.error(
        `❌ Resend OTP failed: ${getErrorMessage(error)}`,
      );
      throw error;
    }
  }

  /**
   * ═════════════════════════════════════════════════════════
   * DASHBOARD ENDPOINTS (Protected - Require JWT)
   * ═════════════════════════════════════════════════════════
   */

  /**
   * Get client's company information
   * @param req Request with JWT payload containing company_ids
   */
  @Get('company')
  @UseGuards(JwtAuthGuard)
  @HttpCode(200)
  async getCompanyInfo(@Req() req: Request): Promise<any> {
    this.logger.log(`GET /client-portal/company`);

    try {
      const companyIds = this.getCompanyIds(req);
      if (!companyIds || companyIds.length === 0) {
        throw new BadRequestException('No company access found');
      }

      // Get first company (main company)
      const companyId = companyIds[0];

      // ✅ ROBUST FIX: Validate company exists in company_client_links BEFORE querying company data
      this.logger.log(`  [ROBUST] Validating company ${companyId} in company_client_links...`);
      const clientLink = await this.companyClientLinkRepository.findOne({
        where: { company_id: companyId } as any,
      });

      if (!clientLink) {
        this.logger.warn(`  [ROBUST] Company ${companyId} NOT found in company_client_links`);
        throw new BadRequestException('No company assigned to this client');
      }

      this.logger.log(`  [ROBUST] ✅ Company ${companyId} validated successfully`);

      const result = await this.clientPortalService.getCompanyInfo(companyId);
      return { success: true, data: result };
    } catch (error) {
      // ✅ FIX: Use error helper
      this.logger.error(
        `❌ Get company failed: ${getErrorMessage(error)}`,
      );
      throw error;
    }
  }

  /**
   * Get company branches
   * @param req Request with JWT payload
   */
  @Get('branches')
  @UseGuards(JwtAuthGuard)
  @HttpCode(200)
  async getBranches(@Req() req: Request): Promise<any> {
    this.logger.log(`GET /client-portal/branches`);

    try {
      const companyIds = this.getCompanyIds(req);
      if (!companyIds || companyIds.length === 0) {
        throw new BadRequestException('No company access found');
      }

      const companyId = companyIds[0];
      const result = await this.clientPortalService.getBranches(companyId);
      return { success: true, data: result };
    } catch (error) {
      // ✅ FIX: Use error helper
      this.logger.error(
        `❌ Get branches failed: ${getErrorMessage(error)}`,
      );
      throw error;
    }
  }

  /**
   * Get audit requests for company
   * @param req Request with JWT payload
   * @param query Pagination and filter options
   */
  @Get('audits')
  @UseGuards(JwtAuthGuard)
  @HttpCode(200)
  async getAudits(
    @Req() req: Request,
    @Query() query: ListClientAuditsDto,
  ): Promise<any> {
    this.logger.log(
      `GET /client-portal/audits (page=${query.page}, status=${query.status})`,
    );

    try {
      const companyIds = this.getCompanyIds(req);
      if (!companyIds || companyIds.length === 0) {
        throw new BadRequestException('No company access found');
      }

      const companyId = companyIds[0];
      const result = await this.clientPortalService.getAudits(companyId, {
        status: query.status,
        limit: query.limit,
        page: query.page,
        sort_by: query.sort_by,
        sort_order: query.sort_order,
      });
      return { success: true, data: result };
    } catch (error) {
      // ✅ FIX: Use error helper
      this.logger.error(
        `❌ Get audits failed: ${getErrorMessage(error)}`,
      );
      throw error;
    }
  }

  /**
   * Get audit progress timeline
   * @param req Request with JWT payload
   * @param auditId Audit request ID
   */
  @Get('audits/:id/progress')
  @UseGuards(JwtAuthGuard)
  @HttpCode(200)
  async getAuditProgress(
    @Param('id') auditId: string,
    @Req() req: Request,
  ): Promise<any> {
    this.logger.log(`GET /client-portal/audits/${auditId}/progress`);

    try {
      const companyIds = this.getCompanyIds(req);
      if (!companyIds || companyIds.length === 0) {
        throw new BadRequestException('No company access found');
      }

      const companyId = companyIds[0];
      const result = await this.clientPortalService.getAuditProgress(
        parseInt(auditId),
        companyId,
      );
      return { success: true, data: result };
    } catch (error) {
      // ✅ FIX: Use error helper
      this.logger.error(
        `❌ Get audit progress failed: ${getErrorMessage(error)}`,
      );
      throw error;
    }
  }

  /**
   * Get audit report
   * @param req Request with JWT payload
   * @param auditId Audit request ID
   */
  @Get('audits/:id/report')
  @UseGuards(JwtAuthGuard)
  @HttpCode(200)
  async getAuditReport(
    @Param('id') auditId: string,
    @Req() req: Request,
  ): Promise<any> {
    this.logger.log(`GET /client-portal/audits/${auditId}/report`);

    try {
      const companyIds = this.getCompanyIds(req);
      if (!companyIds || companyIds.length === 0) {
        throw new BadRequestException('No company access found');
      }

      const companyId = companyIds[0];
      const result = await this.clientPortalService.getAuditReport(
        parseInt(auditId),
        companyId,
      );
      return { success: true, data: result };
    } catch (error) {
      // ✅ FIX: Use error helper
      this.logger.error(
        `❌ Get audit report failed: ${getErrorMessage(error)}`,
      );
      throw error;
    }
  }

  /**
   * Get certificates
   * @param req Request with JWT payload
   */
  @Get('certificates')
  @UseGuards(JwtAuthGuard)
  @HttpCode(200)
  async getCertificates(@Req() req: Request): Promise<any> {
    this.logger.log(`GET /client-portal/certificates`);

    try {
      const companyIds = this.getCompanyIds(req);
      if (!companyIds || companyIds.length === 0) {
        throw new BadRequestException('No company access found');
      }

      const companyId = companyIds[0];
      const result = await this.clientPortalService.getCertificates(companyId);
      return { success: true, data: result };
    } catch (error) {
      // ✅ FIX: Use error helper
      this.logger.error(
        `❌ Get certificates failed: ${getErrorMessage(error)}`,
      );
      throw error;
    }
  }

  /**
   * ═════════════════════════════════════════════════════════
   * HELPER METHODS
   * ═════════════════════════════════════════════════════════
   */

  /**
   * Extract user ID from JWT payload
   */
  private getCurrentUserId(req: Request): number {
    const user = req.user as any;
    return user?.id ?? user?.userId ?? user?.sub;
  }

  /**
   * Extract company IDs from JWT payload (array of company IDs this client has access to)
   */
  private getCompanyIds(req: Request): number[] {
    const user = req.user as any;
    return user?.company_ids ?? [];
  }
}