import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Usage } from './entities/recruiter_cv_usage.entity';
import { ConfigSettingService } from '../config_setting/config_setting.service';

@Injectable()
export class RecruiterCvUsageService {
  constructor(
    @InjectRepository(Usage)
    private usageRepository: Repository<Usage>,
    private configSettingService: ConfigSettingService,
  ) {}

  async getUsageByRecruiterId(recruiterId: number) {
    try {
      const usage = await this.usageRepository
        .createQueryBuilder('usage')
        .where('usage.recruiter_id = :recruiterId', { recruiterId })
        .getOne();

      // For free users, dynamically calculate remaining based on current config
      if (usage && usage.plan_type === 'free') {
        const configFreeLimit =
          await this.configSettingService.getCvLimitFree();
        usage.total_cv_limit = configFreeLimit;
        usage.remaining_cv_downloads = Math.max(
          0,
          configFreeLimit - usage.used_cv_downloads,
        );
      }

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

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

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

      // Get free CV limit from config
      const freeLimit = await this.configSettingService.getCvLimitFree();

      // Create new usage record
      const newUsage = {
        recruiter_id: recruiterId,
        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(Usage)
        .values(newUsage)
        .execute();

      const createdUsage = await this.getUsageByRecruiterId(recruiterId);

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

  async checkDownloadLimit(recruiterId: number) {
    try {
      let usageResult = await this.getUsageByRecruiterId(recruiterId);

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

      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
          },
        };
      }

      // DYNAMIC LIMIT: For free users, always read fresh from config_settings
      let currentLimit = usage.total_cv_limit;
      let remainingDownloads = usage.remaining_cv_downloads;

      if (usage.plan_type === 'free') {
        // Get current free limit from config (may have changed)
        const configFreeLimit =
          await this.configSettingService.getCvLimitFree();
        currentLimit = configFreeLimit;
        // Calculate remaining: config_limit - used_downloads
        remainingDownloads = Math.max(
          0,
          configFreeLimit - usage.used_cv_downloads,
        );
      }

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

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

  async incrementDownloadCount(recruiterId: number) {
    try {
      const usageResult = await this.getUsageByRecruiterId(recruiterId);

      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(Usage)
          .set({
            used_cv_downloads: usage.used_cv_downloads + 1,
            last_download_at: new Date(),
          })
          .where('recruiter_id = :recruiterId', { recruiterId })
          .execute();

        const updatedUsage = await this.getUsageByRecruiterId(recruiterId);

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

      // For FREE users: Only increment used_cv_downloads
      // remaining_cv_downloads will be calculated dynamically from config
      if (usage.plan_type === 'free') {
        // Get current limit from config to validate
        const configFreeLimit =
          await this.configSettingService.getCvLimitFree();
        const currentRemaining = Math.max(
          0,
          configFreeLimit - usage.used_cv_downloads,
        );

        if (currentRemaining <= 0) {
          throw new HttpException(
            'CV download limit reached',
            HttpStatus.FORBIDDEN,
          );
        }

        // Only update used count - remaining is calculated dynamically
        await this.usageRepository
          .createQueryBuilder()
          .update(Usage)
          .set({
            used_cv_downloads: usage.used_cv_downloads + 1,
            last_download_at: new Date(),
          })
          .where('recruiter_id = :recruiterId', { recruiterId })
          .execute();

        const updatedUsage = await this.getUsageByRecruiterId(recruiterId);

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

      // For PAID plans: Update both used and remaining (static limit)
      if (usage.remaining_cv_downloads <= 0) {
        throw new HttpException(
          'CV download limit reached',
          HttpStatus.FORBIDDEN,
        );
      }

      await this.usageRepository
        .createQueryBuilder()
        .update(Usage)
        .set({
          used_cv_downloads: usage.used_cv_downloads + 1,
          remaining_cv_downloads: usage.remaining_cv_downloads - 1,
          last_download_at: new Date(),
        })
        .where('recruiter_id = :recruiterId', { recruiterId })
        .execute();

      // Fetch updated usage
      const updatedUsage = await this.getUsageByRecruiterId(recruiterId);

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

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

      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(Usage)
        .set({
          plan_type: planType,
          total_cv_limit: newLimit,
          remaining_cv_downloads: newRemainingDownloads,
          plan_start_date: new Date(),
          plan_end_date: planEndDate || null,
        })
        .where('recruiter_id = :recruiterId', { recruiterId })
        .execute();

      const updatedUsage = await this.getUsageByRecruiterId(recruiterId);

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

  async resetUsage(recruiterId: number) {
    try {
      const usageResult = await this.getUsageByRecruiterId(recruiterId);

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

      const usage = usageResult.data;

      await this.usageRepository
        .createQueryBuilder()
        .update(Usage)
        .set({
          used_cv_downloads: 0,
          remaining_cv_downloads: usage.total_cv_limit,
        })
        .where('recruiter_id = :recruiterId', { recruiterId })
        .execute();

      const updatedUsage = await this.getUsageByRecruiterId(recruiterId);

      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,
      };
    }
  }
}
