import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, DataSource } from 'typeorm';
import { AssociateCvUsage } from './entities/associate_cv_usage.entity';

@Injectable()
export class AssociateCvUsageService {
  constructor(
    @InjectRepository(AssociateCvUsage)
    private usageRepository: Repository<AssociateCvUsage>,
    private dataSource: DataSource,
  ) {}

  async getUsageByAssociateId(associateId: number) {
    try {
      const usage = await this.usageRepository
        .createQueryBuilder('usage')
        .where('usage.associate_id = :associateId', { associateId })
        .getOne();

      return {
        success: true,
        data: usage,
      };
    } catch (error: any) {
      return {
        success: false,
        error: error.message,
      };
    }
  }

  async initializeAssociateUsage(associateId: number) {
    try {
      // Check if usage already exists
      const existingUsage = await this.usageRepository
        .createQueryBuilder('usage')
        .where('usage.associate_id = :associateId', { associateId })
        .getOne();

      if (existingUsage) {
        return {
          success: true,
          data: existingUsage,
          message: 'Usage already initialized',
        };
      }

      // Associates get FREE plan with 100 CV downloads by default (same as recruiters)
      const freeLimit = 100;
      const newUsage = {
        associate_id: associateId,
        plan_type: 'free',
        total_cv_limit: freeLimit,
        used_cv_downloads: 0,
        remaining_cv_downloads: freeLimit,
        plan_start_date: new Date(),
        plan_end_date: null,
      };

      await this.usageRepository
        .createQueryBuilder()
        .insert()
        .into(AssociateCvUsage)
        .values(newUsage)
        .execute();

      const createdUsage = await this.getUsageByAssociateId(associateId);

      return {
        success: true,
        data: createdUsage.data,
        message: 'Usage initialized successfully',
      };
    } catch (error: any) {
      return {
        success: false,
        error: error.message,
      };
    }
  }

  async checkDownloadLimit(associateId: number) {
    try {
      let usageResult = await this.getUsageByAssociateId(associateId);

      // If no usage record exists, initialize it
      if (!usageResult.data) {
        usageResult = await this.initializeAssociateUsage(associateId);
      }

      if (!usageResult.success || !usageResult.data) {
        throw new HttpException(
          'Failed to fetch usage data',
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }

      const usage = usageResult.data;

      // Check if plan is unlimited (total_cv_limit = -1)
      if (usage.total_cv_limit === -1) {
        return {
          success: true,
          canDownload: true,
          message: 'Download allowed (Unlimited plan)',
          usage: {
            plan_type: usage.plan_type,
            total_cv_limit: usage.total_cv_limit,
            used_cv_downloads: usage.used_cv_downloads,
            remaining_cv_downloads: -1, // Unlimited
          },
        };
      }

      // Check if associate has remaining downloads
      if (usage.remaining_cv_downloads <= 0) {
        return {
          success: false,
          canDownload: false,
          message: 'CV download limit reached. Please upgrade your plan.',
          usage: {
            plan_type: usage.plan_type,
            total_cv_limit: usage.total_cv_limit,
            used_cv_downloads: usage.used_cv_downloads,
            remaining_cv_downloads: usage.remaining_cv_downloads,
          },
        };
      }

      return {
        success: true,
        canDownload: true,
        message: 'Download allowed',
        usage: {
          plan_type: usage.plan_type,
          total_cv_limit: usage.total_cv_limit,
          used_cv_downloads: usage.used_cv_downloads,
          remaining_cv_downloads: usage.remaining_cv_downloads,
        },
      };
    } catch (error: any) {
      return {
        success: false,
        canDownload: false,
        error: error.message,
      };
    }
  }

  async incrementDownloadCount(associateId: number) {
    try {
      let usageResult = await this.getUsageByAssociateId(associateId);

      // If no usage record exists, initialize it first
      if (!usageResult.data) {
        usageResult = await this.initializeAssociateUsage(associateId);
      }

      if (!usageResult.success || !usageResult.data) {
        throw new HttpException('Usage record not found', HttpStatus.NOT_FOUND);
      }

      const usage = usageResult.data;

      // If plan is unlimited (total_cv_limit = -1), only increment used count
      if (usage.total_cv_limit === -1) {
        await this.usageRepository
          .createQueryBuilder()
          .update(AssociateCvUsage)
          .set({
            used_cv_downloads: usage.used_cv_downloads + 1,
            last_download_at: new Date(),
          })
          .where('associate_id = :associateId', { associateId })
          .execute();

        const updatedUsage = await this.getUsageByAssociateId(associateId);

        return {
          success: true,
          data: updatedUsage.data,
          message: 'Download count incremented successfully (Unlimited plan)',
        };
      }

      // Check if there are remaining downloads
      if (usage.remaining_cv_downloads <= 0) {
        throw new HttpException(
          'CV download limit reached',
          HttpStatus.FORBIDDEN,
        );
      }

      // Update the usage record
      await this.usageRepository
        .createQueryBuilder()
        .update(AssociateCvUsage)
        .set({
          used_cv_downloads: usage.used_cv_downloads + 1,
          remaining_cv_downloads: usage.remaining_cv_downloads - 1,
          last_download_at: new Date(),
        })
        .where('associate_id = :associateId', { associateId })
        .execute();

      // Fetch updated usage
      const updatedUsage = await this.getUsageByAssociateId(associateId);

      return {
        success: true,
        data: updatedUsage.data,
        message: 'Download count incremented successfully',
      };
    } catch (error: any) {
      return {
        success: false,
        error: error.message,
      };
    }
  }

  async upgradePlan(
    associateId: number,
    planType: string,
    newLimit: number,
    planEndDate?: Date,
  ) {
    try {
      const usageResult = await this.getUsageByAssociateId(associateId);

      if (!usageResult.success || !usageResult.data) {
        throw new HttpException('Usage record not found', HttpStatus.NOT_FOUND);
      }

      const usage = usageResult.data;

      // Calculate new remaining downloads
      const additionalDownloads = newLimit - usage.total_cv_limit;
      const newRemainingDownloads =
        usage.remaining_cv_downloads + additionalDownloads;

      await this.usageRepository
        .createQueryBuilder()
        .update(AssociateCvUsage)
        .set({
          plan_type: planType,
          total_cv_limit: newLimit,
          remaining_cv_downloads: newRemainingDownloads,
          plan_start_date: new Date(),
          plan_end_date: planEndDate || null,
        })
        .where('associate_id = :associateId', { associateId })
        .execute();

      const updatedUsage = await this.getUsageByAssociateId(associateId);

      return {
        success: true,
        data: updatedUsage.data,
        message: `Plan upgraded to ${planType} successfully`,
      };
    } catch (error: any) {
      return {
        success: false,
        error: error.message,
      };
    }
  }

  async resetUsage(associateId: number) {
    try {
      const usageResult = await this.getUsageByAssociateId(associateId);

      if (!usageResult.success || !usageResult.data) {
        throw new HttpException('Usage record not found', HttpStatus.NOT_FOUND);
      }

      const usage = usageResult.data;

      await this.usageRepository
        .createQueryBuilder()
        .update(AssociateCvUsage)
        .set({
          used_cv_downloads: 0,
          remaining_cv_downloads: usage.total_cv_limit,
        })
        .where('associate_id = :associateId', { associateId })
        .execute();

      const updatedUsage = await this.getUsageByAssociateId(associateId);

      return {
        success: true,
        data: updatedUsage.data,
        message: 'Usage reset successfully',
      };
    } catch (error: any) {
      return {
        success: false,
        error: error.message,
      };
    }
  }

  async getAllUsages() {
    try {
      const usages = await this.usageRepository
        .createQueryBuilder('usage')
        .orderBy('usage.created_at', 'DESC')
        .getMany();

      return {
        success: true,
        data: usages,
      };
    } catch (error: any) {
      return {
        success: false,
        error: error.message,
      };
    }
  }
}
