import db from '../config/database';
import { logger } from '../utils/logger';
import {
  Certificate,
  CertificateCreateInput,
  CertificateUpdateInput,
  CertificateQueryOptions,
  CertificateStatus,
  CertificateType,
} from '../models/Certificate';

/**
 * CertificateService - 证书管理服务
 * 
 * [BE-COM001] 证书存储接口
 * @description 管理商品合规证书的存储、查询、更新和删除
 * 
 * 功能定位：
 * - 证书 CRUD 操作
 * - 证书到期提醒
 * - 证书状态管理
 * 
 * 安全约束：
 * - 所有操作必须携带五元组追踪信息
 * - 状态变更必须通过 PENDING_REVIEW -> APPROVED 流程
 * 
 * @author AI-Backend-7
 * @taskId BE-COM001
 */
export class CertificateService {
  private static readonly TABLE_NAME = 'cf_certificate';

  /**
   * 初始化数据库表
   * 遵循幂等性原则：使用 hasTable 前置校验
   */
  static async initTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.TABLE_NAME);
    if (!hasTable) {
      logger.info(`[CertificateService] Creating ${this.TABLE_NAME} table...`);
      await db.schema.createTable(this.TABLE_NAME, (table) => {
        table.string('id', 36).primary();
        table.string('tenant_id', 64).notNullable().index();
        table.string('shop_id', 64).notNullable().index();
        table.string('task_id', 64);
        table.string('trace_id', 64).notNullable();
        table.enum('business_type', ['TOC', 'TOB']).notNullable();
        
        table.string('certificate_name', 255).notNullable();
        table.enum('certificate_type', [
          'CE', 'FCC', 'ROHS', 'ISO9001', 'ISO14001',
          'FDA', 'UL', 'CCC', 'EXPORT_LICENSE', 'ORIGIN', 'OTHER'
        ]).notNullable();
        table.string('certificate_no', 100).notNullable();
        table.string('product_id', 64).index();
        table.string('product_name', 255);
        table.string('issuer', 255).notNullable();
        table.date('issue_date').notNullable();
        table.date('expiry_date').notNullable().index();
        table.enum('status', [
          'PENDING_REVIEW', 'APPROVED', 'REJECTED', 'EXPIRED', 'REVOKED'
        ]).defaultTo('PENDING_REVIEW').notNullable();
        table.string('file_url', 500);
        table.string('file_hash', 128);
        table.text('remarks');
        table.timestamp('created_at').defaultTo(db.fn.now());
        table.timestamp('updated_at').defaultTo(db.fn.now());
        
        table.index(['tenant_id', 'shop_id'], 'idx_cert_tenant_shop');
        table.index(['tenant_id', 'status'], 'idx_cert_tenant_status');
        table.index(['expiry_date', 'status'], 'idx_cert_expiry_status');
      });
      logger.info(`[CertificateService] Table ${this.TABLE_NAME} created`);
    }
  }

  /**
   * 创建证书
   * @param input 证书创建输入
   * @returns 创建的证书ID
   */
  static async create(input: CertificateCreateInput): Promise<string> {
    const id = this.generateId();
    const now = new Date();

    const certificate: Record<string, any> = {
      id,
      tenant_id: input.tenantId,
      shop_id: input.shopId,
      task_id: input.taskId || null,
      trace_id: input.traceId,
      business_type: input.businessType,
      certificate_name: input.certificateName,
      certificate_type: input.certificateType,
      certificate_no: input.certificateNo,
      product_id: input.productId || null,
      product_name: input.productName || null,
      issuer: input.issuer,
      issue_date: input.issueDate,
      expiry_date: input.expiryDate,
      status: 'PENDING_REVIEW',
      file_url: input.fileUrl || null,
      file_hash: input.fileHash || null,
      remarks: input.remarks || null,
      created_at: now,
      updated_at: now,
    };

    await db(this.TABLE_NAME).insert(certificate);

    logger.info(`[CertificateService] Certificate created: id=${id}, tenantId=${input.tenantId}, shopId=${input.shopId}, traceId=${input.traceId}, type=${input.certificateType}, no=${input.certificateNo}`);

    return id;
  }

  /**
   * 根据ID获取证书
   * @param tenantId 租户ID
   * @param id 证书ID
   * @returns 证书信息
   */
  static async getById(tenantId: string, id: string): Promise<Certificate | null> {
    const row = await db(this.TABLE_NAME)
      .where({ id, tenant_id: tenantId })
      .first();

    if (!row) return null;

    return this.mapRowToCertificate(row);
  }

  /**
   * 查询证书列表
   * @param options 查询选项
   * @returns 证书列表和总数
   */
  static async query(
    options: CertificateQueryOptions
  ): Promise<{ data: Certificate[]; total: number }> {
    const { page = 1, pageSize = 20 } = options;
    const offset = (page - 1) * pageSize;

    let query = db(this.TABLE_NAME)
      .where('tenant_id', options.tenantId);

    if (options.shopId) {
      query = query.where('shop_id', options.shopId);
    }
    if (options.productId) {
      query = query.where('product_id', options.productId);
    }
    if (options.certificateType) {
      query = query.where('certificate_type', options.certificateType);
    }
    if (options.status) {
      query = query.where('status', options.status);
    }
    if (options.expiryFrom) {
      query = query.where('expiry_date', '>=', options.expiryFrom);
    }
    if (options.expiryTo) {
      query = query.where('expiry_date', '<=', options.expiryTo);
    }

    const totalQuery = query.clone();
    const [{ count }] = await totalQuery.count('* as count');
    const total = Number(count);

    const rows = await query
      .orderBy('created_at', 'desc')
      .limit(pageSize)
      .offset(offset);

    const data = rows.map(row => this.mapRowToCertificate(row));

    logger.info(`[CertificateService] Query certificates: tenantId=${options.tenantId}, shopId=${options.shopId}, status=${options.status}, total=${total}, page=${page}, pageSize=${pageSize}`);

    return { data, total };
  }

  /**
   * 更新证书
   * @param tenantId 租户ID
   * @param id 证书ID
   * @param input 更新输入
   * @param traceId 追踪ID
   * @returns 是否更新成功
   */
  static async update(
    tenantId: string,
    id: string,
    input: CertificateUpdateInput,
    traceId: string
  ): Promise<boolean> {
    const updateData: Record<string, any> = {
      updated_at: new Date(),
    };

    if (input.certificateName !== undefined) {
      updateData.certificate_name = input.certificateName;
    }
    if (input.certificateType !== undefined) {
      updateData.certificate_type = input.certificateType;
    }
    if (input.certificateNo !== undefined) {
      updateData.certificate_no = input.certificateNo;
    }
    if (input.productId !== undefined) {
      updateData.product_id = input.productId;
    }
    if (input.productName !== undefined) {
      updateData.product_name = input.productName;
    }
    if (input.issuer !== undefined) {
      updateData.issuer = input.issuer;
    }
    if (input.issueDate !== undefined) {
      updateData.issue_date = input.issueDate;
    }
    if (input.expiryDate !== undefined) {
      updateData.expiry_date = input.expiryDate;
    }
    if (input.status !== undefined) {
      updateData.status = input.status;
    }
    if (input.fileUrl !== undefined) {
      updateData.file_url = input.fileUrl;
    }
    if (input.fileHash !== undefined) {
      updateData.file_hash = input.fileHash;
    }
    if (input.remarks !== undefined) {
      updateData.remarks = input.remarks;
    }

    const affectedRows = await db(this.TABLE_NAME)
      .where({ id, tenant_id: tenantId })
      .update(updateData);

    logger.info(`[CertificateService] Certificate updated: id=${id}, tenantId=${tenantId}, traceId=${traceId}, affectedRows=${affectedRows}`);

    return affectedRows > 0;
  }

  /**
   * 删除证书
   * @param tenantId 租户ID
   * @param id 证书ID
   * @param traceId 追踪ID
   * @returns 是否删除成功
   */
  static async delete(tenantId: string, id: string, traceId: string): Promise<boolean> {
    const affectedRows = await db(this.TABLE_NAME)
      .where({ id, tenant_id: tenantId })
      .delete();

    logger.info(`[CertificateService] Certificate deleted: id=${id}, tenantId=${tenantId}, traceId=${traceId}, affectedRows=${affectedRows}`);

    return affectedRows > 0;
  }

  /**
   * 更新证书状态
   * @param tenantId 租户ID
   * @param id 证书ID
   * @param status 新状态
   * @param traceId 追踪ID
   * @returns 是否更新成功
   */
  static async updateStatus(
    tenantId: string,
    id: string,
    status: CertificateStatus,
    traceId: string
  ): Promise<boolean> {
    const affectedRows = await db(this.TABLE_NAME)
      .where({ id, tenant_id: tenantId })
      .update({
        status,
        updated_at: new Date(),
      });

    logger.info(`[CertificateService] Certificate status updated: id=${id}, tenantId=${tenantId}, traceId=${traceId}, newStatus=${status}`);

    return affectedRows > 0;
  }

  /**
   * 获取即将到期的证书
   * @param days 天数阈值（默认30天）
   * @returns 即将到期的证书列表
   */
  static async getExpiringCertificates(days: number = 30): Promise<Certificate[]> {
    const expiryDate = new Date();
    expiryDate.setDate(expiryDate.getDate() + days);

    const rows = await db(this.TABLE_NAME)
      .where('status', 'APPROVED')
      .where('expiry_date', '<=', expiryDate)
      .where('expiry_date', '>=', new Date())
      .orderBy('expiry_date', 'asc');

    return rows.map(row => this.mapRowToCertificate(row));
  }

  /**
   * 自动标记过期证书
   * @returns 更新的证书数量
   */
  static async markExpiredCertificates(): Promise<number> {
    const now = new Date();

    const affectedRows = await db(this.TABLE_NAME)
      .where('status', 'APPROVED')
      .where('expiry_date', '<', now)
      .update({
        status: 'EXPIRED',
        updated_at: now,
      });

    logger.info(`[CertificateService] Expired certificates marked: count=${affectedRows}`);

    return affectedRows;
  }

  /**
   * 根据商品ID获取证书列表
   * @param tenantId 租户ID
   * @param productId 商品ID
   * @returns 证书列表
   */
  static async getByProductId(tenantId: string, productId: string): Promise<Certificate[]> {
    const rows = await db(this.TABLE_NAME)
      .where({ tenant_id: tenantId, product_id: productId })
      .orderBy('created_at', 'desc');

    return rows.map(row => this.mapRowToCertificate(row));
  }

  /**
   * 检查商品是否有有效的合规证书
   * @param tenantId 租户ID
   * @param productId 商品ID
   * @param requiredTypes 需要的证书类型
   * @returns 合规检查结果
   */
  static async checkCompliance(
    tenantId: string,
    productId: string,
    requiredTypes: CertificateType[]
  ): Promise<{ compliant: boolean; missing: CertificateType[]; certificates: Certificate[] }> {
    const certificates = await this.getByProductId(tenantId, productId);
    const validCertificates = certificates.filter(
      cert => cert.status === 'APPROVED' && new Date(cert.expiryDate) > new Date()
    );

    const existingTypes = new Set(validCertificates.map(cert => cert.certificateType));
    const missing = requiredTypes.filter(type => !existingTypes.has(type));

    return {
      compliant: missing.length === 0,
      missing,
      certificates: validCertificates,
    };
  }

  /**
   * 生成唯一ID
   */
  private static generateId(): string {
    return `CERT-${Date.now()}-${Math.random().toString(36).substring(2, 10)}`;
  }

  /**
   * 将数据库行映射为证书对象
   */
  private static mapRowToCertificate(row: Record<string, any>): Certificate {
    return {
      id: row.id,
      tenantId: row.tenant_id,
      shopId: row.shop_id,
      taskId: row.task_id,
      traceId: row.trace_id,
      businessType: row.business_type,
      certificateName: row.certificate_name,
      certificateType: row.certificate_type,
      certificateNo: row.certificate_no,
      productId: row.product_id,
      productName: row.product_name,
      issuer: row.issuer,
      issueDate: row.issue_date,
      expiryDate: row.expiry_date,
      status: row.status,
      fileUrl: row.file_url,
      fileHash: row.file_hash,
      remarks: row.remarks,
      createdAt: row.created_at,
      updatedAt: row.updated_at,
    };
  }
}
