import { Injectable, Inject, NotFoundException, BadRequestException, Logger } from '@nestjs/common';
import { ISSUER_REPOSITORY, IIssuerRepository } from '../../domain/repositories/issuer.repository.interface';
import { STORE_REPOSITORY, IStoreRepository } from '../../domain/repositories/store.repository.interface';
import { COUPON_REPOSITORY, ICouponRepository } from '../../domain/repositories/coupon.repository.interface';
import { CREDIT_METRIC_REPOSITORY, ICreditMetricRepository } from '../../domain/repositories/credit-metric.repository.interface';
import { AI_SERVICE_CLIENT, IAiServiceClient } from '../../domain/ports/ai-service.client.interface';
import { Issuer, IssuerStatus } from '../../domain/entities/issuer.entity';
import { CreditMetric } from '../../domain/entities/credit-metric.entity';

export interface ListIssuersFilters {
  page?: number;
  limit?: number;
  status?: string;
  search?: string;
}

export interface IssuerDetailResult {
  issuer: Issuer;
  creditMetric: CreditMetric | null;
  storesCount: number;
  couponsCount: number;
}

export interface AiPreReviewResult {
  issuer: Issuer;
  recommendation: string;
  riskLevel: string;
  reasons: string[];
}

@Injectable()
export class AdminIssuerService {
  private readonly logger = new Logger('AdminIssuerService');

  constructor(
    @Inject(ISSUER_REPOSITORY)
    private readonly issuerRepo: IIssuerRepository,
    @Inject(STORE_REPOSITORY)
    private readonly storeRepo: IStoreRepository,
    @Inject(COUPON_REPOSITORY)
    private readonly couponRepo: ICouponRepository,
    @Inject(CREDIT_METRIC_REPOSITORY)
    private readonly creditMetricRepo: ICreditMetricRepository,
    @Inject(AI_SERVICE_CLIENT)
    private readonly aiServiceClient: IAiServiceClient,
  ) {}

  /**
   * List issuers with pagination, ILIKE search, and status filter.
   */
  async listIssuers(filters: ListIssuersFilters) {
    const page = filters.page || 1;
    const limit = filters.limit || 20;

    const [items, total] = await this.issuerRepo.findAndCount({
      status: filters.status,
      search: filters.search,
      page,
      limit,
    });

    return {
      items,
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  /**
   * Get issuer detail including credit metrics, store count, and coupon count.
   */
  async getIssuerDetail(id: string): Promise<IssuerDetailResult> {
    const issuer = await this.issuerRepo.findById(id);
    if (!issuer) throw new NotFoundException('Issuer not found');

    const creditMetric = await this.creditMetricRepo.findLatestByIssuerId(id);
    const storesCount = await this.storeRepo.count({ issuerId: id });
    const couponsCount = await this.couponRepo.count({ issuerId: id });

    return { issuer, creditMetric, storesCount, couponsCount };
  }

  /**
   * Approve an issuer: set status from PENDING to ACTIVE.
   */
  async approveIssuer(id: string): Promise<Issuer> {
    const issuer = await this.issuerRepo.findById(id);
    if (!issuer) throw new NotFoundException('Issuer not found');

    if (issuer.status !== IssuerStatus.PENDING) {
      throw new BadRequestException(
        `Cannot approve issuer with status "${issuer.status}". Only pending issuers can be approved.`,
      );
    }

    issuer.status = IssuerStatus.ACTIVE;
    return this.issuerRepo.save(issuer);
  }

  /**
   * Reject an issuer: set status from PENDING to REJECTED with reason.
   */
  async rejectIssuer(id: string, reason: string): Promise<Issuer> {
    const issuer = await this.issuerRepo.findById(id);
    if (!issuer) throw new NotFoundException('Issuer not found');

    if (issuer.status !== IssuerStatus.PENDING) {
      throw new BadRequestException(
        `Cannot reject issuer with status "${issuer.status}". Only pending issuers can be rejected.`,
      );
    }

    issuer.status = IssuerStatus.REJECTED;
    issuer.description = issuer.description
      ? `${issuer.description}\n[REJECTED] ${reason}`
      : `[REJECTED] ${reason}`;

    return this.issuerRepo.save(issuer);
  }

  /**
   * Fetch pending issuers and call AI service for pre-review recommendation.
   * Falls back to a simple rule-based recommendation if AI service is unavailable.
   */
  async getAiPreReview(): Promise<AiPreReviewResult[]> {
    const pendingIssuers = await this.issuerRepo.findPending(50);

    if (pendingIssuers.length === 0) {
      return [];
    }

    // Delegate to infrastructure AI service client
    const aiReviews = await this.aiServiceClient.reviewIssuers(
      pendingIssuers.map((i) => ({
        id: i.id,
        companyName: i.companyName,
        businessLicense: i.businessLicense,
        contactName: i.contactName,
        contactPhone: i.contactPhone,
        contactEmail: i.contactEmail,
        description: i.description,
        creditScore: i.creditScore,
        createdAt: i.createdAt,
      })),
    );

    if (aiReviews) {
      return pendingIssuers.map((issuer) => {
        const aiReview = aiReviews.find((r) => r.issuerId === issuer.id);
        return {
          issuer,
          recommendation: aiReview?.recommendation || 'manual_review',
          riskLevel: aiReview?.riskLevel || 'unknown',
          reasons: aiReview?.reasons || ['AI review data not available'],
        };
      });
    }

    // Fallback: simple rule-based pre-review
    this.logger.warn('AI service unavailable, falling back to rule-based review');
    return pendingIssuers.map((issuer) => {
      const reasons: string[] = [];
      let riskLevel = 'low';

      if (!issuer.businessLicense) {
        reasons.push('Missing business license');
        riskLevel = 'high';
      }
      if (!issuer.contactEmail) {
        reasons.push('Missing contact email');
        riskLevel = riskLevel === 'high' ? 'high' : 'medium';
      }
      if (!issuer.description) {
        reasons.push('Missing company description');
      }
      if (Number(issuer.creditScore) < 40) {
        reasons.push('Low credit score');
        riskLevel = 'high';
      }

      const recommendation =
        riskLevel === 'high'
          ? 'reject'
          : riskLevel === 'medium'
            ? 'manual_review'
            : 'approve';

      if (reasons.length === 0) {
        reasons.push('All basic checks passed');
      }

      return { issuer, recommendation, riskLevel, reasons };
    });
  }
}
