import { Injectable } from '@nestjs/common';
import { ContributionAmount } from '../../../domain/value-objects/contribution-amount.vo';
import { UnitOfWork, TransactionClient } from '../unit-of-work/unit-of-work';

export type SystemAccountType = 'OPERATION' | 'PROVINCE' | 'CITY' | 'HEADQUARTERS';

export interface SystemAccount {
  id: bigint;
  accountType: SystemAccountType;
  regionCode: string | null;  // 省/市代码
  name: string;
  contributionBalance: ContributionAmount;
  contributionNeverExpires: boolean;
  version: number;
  createdAt: Date;
  updatedAt: Date;
}

export interface SystemContributionRecord {
  id: bigint;
  systemAccountId: bigint;
  sourceAdoptionId: bigint;
  sourceAccountSequence: string;
  sourceType: string;       // 来源类型：FIXED_RATE / LEVEL_OVERFLOW / LEVEL_NO_ANCESTOR / BONUS_TIER_1/2/3
  levelDepth: number | null; // 层级深度（1-15），仅对层级相关类型有效
  distributionRate: number;
  amount: ContributionAmount;
  effectiveDate: Date;
  expireDate: Date | null;
  isExpired: boolean;
  createdAt: Date;
}

@Injectable()
export class SystemAccountRepository {
  constructor(private readonly unitOfWork: UnitOfWork) {}

  private get client(): TransactionClient {
    return this.unitOfWork.getClient();
  }

  /**
   * 根据 accountType + regionCode 查找系统账户
   * 注意：由于 regionCode 是可选字段，使用 findFirst 替代 findUnique
   */
  async findByTypeAndRegion(
    accountType: SystemAccountType,
    regionCode: string | null,
  ): Promise<SystemAccount | null> {
    const record = await this.client.systemAccount.findFirst({
      where: {
        accountType,
        regionCode: regionCode === null ? { equals: null } : regionCode,
      },
    });

    if (!record) {
      return null;
    }

    return this.toSystemAccount(record);
  }

  /**
   * 根据类型查找所有账户（如查找所有 CITY 类型账户）
   */
  async findByType(accountType: SystemAccountType): Promise<SystemAccount[]> {
    const records = await this.client.systemAccount.findMany({
      where: { accountType },
      orderBy: { regionCode: 'asc' },
    });

    return records.map((r) => this.toSystemAccount(r));
  }

  async findAll(): Promise<SystemAccount[]> {
    const records = await this.client.systemAccount.findMany({
      orderBy: [{ accountType: 'asc' }, { regionCode: 'asc' }],
    });

    return records.map((r) => this.toSystemAccount(r));
  }

  /**
   * 确保基础账户存在
   */
  async ensureSystemAccountsExist(): Promise<void> {
    const accounts: { accountType: SystemAccountType; name: string }[] = [
      { accountType: 'OPERATION', name: '运营账户' },
      { accountType: 'HEADQUARTERS', name: '总部账户' },
    ];

    for (const account of accounts) {
      // 由于 regionCode 是 nullable，使用 findFirst + create 替代 upsert
      const existing = await this.client.systemAccount.findFirst({
        where: {
          accountType: account.accountType,
          regionCode: { equals: null },
        },
      });

      if (!existing) {
        await this.client.systemAccount.create({
          data: {
            accountType: account.accountType,
            regionCode: null,
            name: account.name,
            contributionBalance: 0,
            contributionNeverExpires: true,
          },
        });
      }
    }
  }

  /**
   * 添加算力到系统账户（动态创建账户）
   */
  async addContribution(
    accountType: SystemAccountType,
    regionCode: string | null,
    amount: ContributionAmount,
  ): Promise<void> {
    const name = this.getAccountName(accountType, regionCode);

    // 由于 regionCode 是 nullable，使用 findFirst + create/update 替代 upsert
    const existing = await this.client.systemAccount.findFirst({
      where: {
        accountType,
        regionCode: regionCode === null ? { equals: null } : regionCode,
      },
    });

    if (existing) {
      await this.client.systemAccount.update({
        where: { id: existing.id },
        data: {
          contributionBalance: { increment: amount.value },
        },
      });
    } else {
      await this.client.systemAccount.create({
        data: {
          accountType,
          regionCode,
          name,
          contributionBalance: amount.value,
          contributionNeverExpires: true,
        },
      });
    }
  }

  /**
   * 生成账户名称
   */
  private getAccountName(accountType: SystemAccountType, regionCode: string | null): string {
    if (!regionCode) {
      const names: Record<SystemAccountType, string> = {
        OPERATION: '运营账户',
        PROVINCE: '省公司账户',
        CITY: '市公司账户',
        HEADQUARTERS: '总部账户',
      };
      return names[accountType] || accountType;
    }
    return `${regionCode}账户`;
  }

  /**
   * 减少系统账户算力
   */
  async subtractContribution(
    accountType: SystemAccountType,
    regionCode: string | null,
    amount: ContributionAmount,
  ): Promise<void> {
    const existing = await this.client.systemAccount.findFirst({
      where: {
        accountType,
        regionCode: regionCode === null ? { equals: null } : regionCode,
      },
    });

    if (existing) {
      await this.client.systemAccount.update({
        where: { id: existing.id },
        data: {
          contributionBalance: { decrement: amount.value },
        },
      });
    }
  }

  /**
   * 软删除指定来源认种的明细记录
   */
  async deleteContributionRecordsByAdoption(
    accountType: SystemAccountType,
    regionCode: string | null,
    sourceAdoptionId: bigint,
    sourceAccountSequence: string,
  ): Promise<number> {
    const systemAccount = await this.findByTypeAndRegion(accountType, regionCode);
    if (!systemAccount) {
      return 0;
    }

    const result = await this.client.systemContributionRecord.updateMany({
      where: {
        systemAccountId: systemAccount.id,
        sourceAdoptionId,
        sourceAccountSequence,
        deletedAt: null, // 只软删除未删除的记录
      },
      data: {
        deletedAt: new Date(),
      },
    });

    return result.count;
  }

  async saveContributionRecord(record: {
    accountType: SystemAccountType;
    regionCode: string | null;
    sourceAdoptionId: bigint;
    sourceAccountSequence: string;
    sourceType: string;       // 来源类型
    levelDepth?: number | null; // 层级深度
    distributionRate: number;
    amount: ContributionAmount;
    effectiveDate: Date;
    expireDate?: Date | null;
  }): Promise<SystemContributionRecord> {
    const systemAccount = await this.findByTypeAndRegion(record.accountType, record.regionCode);
    if (!systemAccount) {
      throw new Error(`System account ${record.accountType}:${record.regionCode} not found`);
    }

    const created = await this.client.systemContributionRecord.create({
      data: {
        systemAccountId: systemAccount.id,
        sourceAdoptionId: record.sourceAdoptionId,
        sourceAccountSequence: record.sourceAccountSequence,
        sourceType: record.sourceType,
        levelDepth: record.levelDepth ?? null,
        distributionRate: record.distributionRate,
        amount: record.amount.value,
        effectiveDate: record.effectiveDate,
        expireDate: record.expireDate ?? null,
      },
    });

    return this.toContributionRecord(created);
  }

  async findContributionRecords(
    accountType: SystemAccountType,
    regionCode: string | null,
    page: number,
    pageSize: number,
  ): Promise<{ data: SystemContributionRecord[]; total: number }> {
    const systemAccount = await this.findByTypeAndRegion(accountType, regionCode);
    if (!systemAccount) {
      return { data: [], total: 0 };
    }

    const whereClause = {
      systemAccountId: systemAccount.id,
      deletedAt: null, // 过滤已软删除的记录
    };

    const [records, total] = await Promise.all([
      this.client.systemContributionRecord.findMany({
        where: whereClause,
        skip: (page - 1) * pageSize,
        take: pageSize,
        orderBy: { createdAt: 'desc' },
      }),
      this.client.systemContributionRecord.count({
        where: whereClause,
      }),
    ]);

    return {
      data: records.map((r) => this.toContributionRecord(r)),
      total,
    };
  }

  private toSystemAccount(record: any): SystemAccount {
    return {
      id: record.id,
      accountType: record.accountType as SystemAccountType,
      regionCode: record.regionCode,
      name: record.name,
      contributionBalance: new ContributionAmount(record.contributionBalance),
      contributionNeverExpires: record.contributionNeverExpires,
      version: record.version,
      createdAt: record.createdAt,
      updatedAt: record.updatedAt,
    };
  }

  private toContributionRecord(record: any): SystemContributionRecord {
    return {
      id: record.id,
      systemAccountId: record.systemAccountId,
      sourceAdoptionId: record.sourceAdoptionId,
      sourceAccountSequence: record.sourceAccountSequence,
      sourceType: record.sourceType,
      levelDepth: record.levelDepth,
      distributionRate: record.distributionRate,
      amount: new ContributionAmount(record.amount),
      effectiveDate: record.effectiveDate,
      expireDate: record.expireDate,
      isExpired: record.isExpired,
      createdAt: record.createdAt,
    };
  }
}
