import {
  Controller,
  Get,
  Post,
  Body,
  Param,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import { AssociateCvUsageService } from './associate_cv_usage.service';
import { Public } from '../auth/public.decorator';
import { DataSource } from 'typeorm';
import {
  ApiBearerAuth,
  ApiTags,
  ApiBody,
  ApiParam,
  ApiQuery,
  ApiOperation,
} from '@nestjs/swagger';

@ApiTags('associates/user')
@ApiBearerAuth('access-token')
@Controller('associates/user')
export class AssociateCvUsageController {
  constructor(
    private readonly associateCvUsageService: AssociateCvUsageService,
    private readonly dataSource: DataSource,
  ) {}

  // Helper: Convert user_id to associates.id
  private async getAssociateIdFromUserId(userId: number): Promise<number> {
    const [associate] = await this.dataSource.query(
      'SELECT id FROM associates WHERE user_id = ? LIMIT 1',
      [userId],
    );

    if (!associate) {
      throw new HttpException(
        'Associate not found for this user',
        HttpStatus.NOT_FOUND,
      );
    }

    return associate.id;
  }

  @Public()
  @Get(':userId/cv-usage')
  async getAssociateCvUsage(@Param('userId') userId: string) {
    try {
      // Convert user_id (3) to associates.id (4)
      const userIdNum = parseInt(userId);
      const associateId = await this.getAssociateIdFromUserId(userIdNum);
      const result =
        await this.associateCvUsageService.getUsageByAssociateId(associateId);

      if (!result.success || !result.data) {
        // Initialize usage if not found
        const initResult =
          await this.associateCvUsageService.initializeAssociateUsage(
            associateId,
          );
        return initResult;
      }

      return result;
    } catch (error: any) {
      throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Public()
  @Get(':userId/cv-usage/check')
  async checkAssociateCvLimit(@Param('userId') userId: string) {
    try {
      const userIdNum = parseInt(userId);
      const associateId = await this.getAssociateIdFromUserId(userIdNum);
      const result =
        await this.associateCvUsageService.checkDownloadLimit(associateId);
      return result;
    } catch (error: any) {
      throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Public()
  @Post(':userId/cv-usage/increment')
  @ApiOperation({ summary: 'Increment Download Count' })
  @ApiParam({ name: 'userId', type: String })
  async incrementAssociateCvDownload(@Param('userId') userId: string) {
    try {
      const userIdNum = parseInt(userId);
      const associateId = await this.getAssociateIdFromUserId(userIdNum);
      const result =
        await this.associateCvUsageService.incrementDownloadCount(associateId);
      return result;
    } catch (error: any) {
      throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Public()
  @Post(':userId/cv-usage/initialize')
  async initializeAssociateUsage(@Param('userId') userId: string) {
    try {
      const userIdNum = parseInt(userId);
      const associateId = await this.getAssociateIdFromUserId(userIdNum);
      const result =
        await this.associateCvUsageService.initializeAssociateUsage(
          associateId,
        );
      return result;
    } catch (error: any) {
      throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Public()
  @Post(':userId/cv-usage/upgrade')
  @ApiOperation({ summary: 'Upgrade Plan' })
  @ApiParam({ name: 'userId', type: String })
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        planType: { type: 'string' },
        newLimit: { type: 'number' },
        planEndDate: { type: 'string', format: 'date-time' },
      },
      required: ['planType', 'newLimit'],
    },
  })
  async upgradeAssociatePlan(
    @Param('userId') userId: string,
    @Body() body: { planType: string; newLimit: number; planEndDate?: Date },
  ) {
    try {
      const userIdNum = parseInt(userId);
      const associateId = await this.getAssociateIdFromUserId(userIdNum);
      const result = await this.associateCvUsageService.upgradePlan(
        associateId,
        body.planType,
        body.newLimit,
        body.planEndDate,
      );
      return result;
    } catch (error: any) {
      throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Public()
  @Post(':userId/cv-usage/reset')
  @ApiOperation({ summary: 'Reset Usage' })
  @ApiParam({ name: 'userId', type: String })
  async resetAssociateUsage(@Param('userId') userId: string) {
    try {
      const userIdNum = parseInt(userId);
      const associateId = await this.getAssociateIdFromUserId(userIdNum);
      const result = await this.associateCvUsageService.resetUsage(associateId);
      return result;
    } catch (error: any) {
      throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Public()
  @Get('cv-usage/all')
  async getAllAssociateUsages() {
    try {
      const result = await this.associateCvUsageService.getAllUsages();
      return result;
    } catch (error: any) {
      throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}
