import { Injectable, Inject, Logger } from '@nestjs/common';
import { v4 as uuidv4 } from 'uuid';
import { RuleEngineService } from './rule-engine.service';
import {
  USER_TAG_REPOSITORY,
  UserTagRepository,
} from '../../domain/repositories/user-tag.repository';
import {
  USER_QUERY_REPOSITORY,
  IUserQueryRepository,
} from '../../domain/repositories/user-query.repository';
import {
  UserTagAssignmentEntity,
  UserTagLogEntity,
  TagAction,
} from '../../domain/entities/user-tag.entity';

/**
 * 标签同步结果
 */
export interface TagSyncResult {
  accountSequence: string;
  added: string[]; // 新增的 tagId
  removed: string[]; // 移除的 tagId
  unchanged: string[]; // 未变化的 tagId
}

/**
 * 批量同步结果
 */
export interface BatchSyncResult {
  total: number;
  processed: number;
  results: TagSyncResult[];
  errors: Array<{ accountSequence: string; error: string }>;
}

/**
 * 用户标签服务
 * 负责用户标签的打标、移除、同步等操作
 */
@Injectable()
export class UserTaggingService {
  private readonly logger = new Logger(UserTaggingService.name);

  constructor(
    private readonly ruleEngine: RuleEngineService,
    @Inject(USER_TAG_REPOSITORY)
    private readonly tagRepository: UserTagRepository,
    @Inject(USER_QUERY_REPOSITORY)
    private readonly userQueryRepository: IUserQueryRepository,
  ) {}

  /**
   * 手动给用户打标签
   */
  async assignTag(params: {
    accountSequence: string;
    tagId: string;
    value?: string | null;
    assignedBy: string;
    expiresAt?: Date | null;
    reason?: string;
  }): Promise<void> {
    const tag = await this.tagRepository.findTagById(params.tagId);
    if (!tag) {
      throw new Error(`Tag not found: ${params.tagId}`);
    }

    // 检查是否已有关联
    const existing = await this.tagRepository.getAssignment(
      params.accountSequence,
      params.tagId,
    );

    if (existing) {
      // 更新现有关联的值
      if (params.value !== undefined) {
        const updated = existing.updateValue(params.value);
        await this.tagRepository.saveAssignment(updated);

        // 记录日志
        await this.tagRepository.saveLog(
          UserTagLogEntity.create({
            id: uuidv4(),
            accountSequence: params.accountSequence,
            tagCode: tag.code,
            action: TagAction.UPDATE,
            oldValue: existing.value,
            newValue: params.value,
            reason: params.reason,
            operatorId: params.assignedBy,
          }),
        );
      }
      return;
    }

    // 创建新关联
    const assignment = UserTagAssignmentEntity.createManual({
      id: uuidv4(),
      accountSequence: params.accountSequence,
      tagId: params.tagId,
      value: params.value,
      assignedBy: params.assignedBy,
      expiresAt: params.expiresAt,
    });

    await this.tagRepository.saveAssignment(assignment);

    // 记录日志
    await this.tagRepository.saveLog(
      UserTagLogEntity.create({
        id: uuidv4(),
        accountSequence: params.accountSequence,
        tagCode: tag.code,
        action: TagAction.ASSIGN,
        newValue: params.value,
        reason: params.reason,
        operatorId: params.assignedBy,
      }),
    );
  }

  /**
   * 移除用户标签
   */
  async removeTag(params: {
    accountSequence: string;
    tagId: string;
    operatorId: string;
    reason?: string;
  }): Promise<void> {
    const tag = await this.tagRepository.findTagById(params.tagId);
    if (!tag) {
      throw new Error(`Tag not found: ${params.tagId}`);
    }

    const existing = await this.tagRepository.getAssignment(
      params.accountSequence,
      params.tagId,
    );
    if (!existing) {
      return; // 没有关联，无需移除
    }

    await this.tagRepository.deleteAssignment(
      params.accountSequence,
      params.tagId,
    );

    // 记录日志
    await this.tagRepository.saveLog(
      UserTagLogEntity.create({
        id: uuidv4(),
        accountSequence: params.accountSequence,
        tagCode: tag.code,
        action: TagAction.REMOVE,
        oldValue: existing.value,
        reason: params.reason,
        operatorId: params.operatorId,
      }),
    );
  }

  /**
   * 批量给用户打标签
   */
  async batchAssignTag(params: {
    accountSequences: string[];
    tagId: string;
    value?: string | null;
    assignedBy: string;
    reason?: string;
  }): Promise<{ success: number; failed: number }> {
    let success = 0;
    let failed = 0;

    for (const accountSequence of params.accountSequences) {
      try {
        await this.assignTag({
          accountSequence,
          tagId: params.tagId,
          value: params.value,
          assignedBy: params.assignedBy,
          reason: params.reason,
        });
        success++;
      } catch {
        failed++;
      }
    }

    return { success, failed };
  }

  /**
   * 同步单个用户的自动标签
   * 根据规则引擎评估结果，自动添加/移除标签
   */
  async syncUserAutoTags(accountSequence: string): Promise<TagSyncResult> {
    const result: TagSyncResult = {
      accountSequence,
      added: [],
      removed: [],
      unchanged: [],
    };

    // 获取用户当前的自动标签
    const currentTags = await this.tagRepository.findUserTags(accountSequence);
    const currentAutoTagIds = new Set(
      currentTags
        .filter((t) => t.assignment.isAuto())
        .map((t) => t.tag.id),
    );

    // 评估规则，获取应该有的标签
    const evaluation = await this.ruleEngine.evaluateUserRules(accountSequence);
    const shouldHaveTagIds = new Set(evaluation.matchedTagIds);

    // 计算需要添加和移除的标签
    const toAdd = [...shouldHaveTagIds].filter((id) => !currentAutoTagIds.has(id));
    const toRemove = [...currentAutoTagIds].filter((id) => !shouldHaveTagIds.has(id));
    const unchanged = [...shouldHaveTagIds].filter((id) => currentAutoTagIds.has(id));

    // 添加新标签
    for (const tagId of toAdd) {
      const tag = await this.tagRepository.findTagById(tagId);
      if (!tag) continue;

      const assignment = UserTagAssignmentEntity.createAuto({
        id: uuidv4(),
        accountSequence,
        tagId,
        ruleId: tag.ruleId ?? undefined,
      });
      await this.tagRepository.saveAssignment(assignment);

      // 记录日志
      await this.tagRepository.saveLog(
        UserTagLogEntity.create({
          id: uuidv4(),
          accountSequence,
          tagCode: tag.code,
          action: TagAction.ASSIGN,
          reason: '自动规则匹配',
        }),
      );

      result.added.push(tagId);
    }

    // 移除不再匹配的标签
    for (const tagId of toRemove) {
      const tag = await this.tagRepository.findTagById(tagId);
      if (!tag) continue;

      await this.tagRepository.deleteAssignment(accountSequence, tagId);

      // 记录日志
      await this.tagRepository.saveLog(
        UserTagLogEntity.create({
          id: uuidv4(),
          accountSequence,
          tagCode: tag.code,
          action: TagAction.REMOVE,
          reason: '自动规则不再匹配',
        }),
      );

      result.removed.push(tagId);
    }

    result.unchanged = unchanged;
    return result;
  }

  /**
   * 批量同步用户自动标签
   */
  async batchSyncAutoTags(
    accountSequences: string[],
  ): Promise<BatchSyncResult> {
    const result: BatchSyncResult = {
      total: accountSequences.length,
      processed: 0,
      results: [],
      errors: [],
    };

    for (const accountSequence of accountSequences) {
      try {
        const syncResult = await this.syncUserAutoTags(accountSequence);
        result.results.push(syncResult);
        result.processed++;
      } catch (error) {
        result.errors.push({
          accountSequence,
          error: error instanceof Error ? error.message : String(error),
        });
      }
    }

    return result;
  }

  /**
   * 同步所有用户的自动标签
   * 用于定时任务
   */
  async syncAllAutoTags(options?: {
    batchSize?: number;
    onProgress?: (processed: number, total: number) => void;
  }): Promise<BatchSyncResult> {
    const batchSize = options?.batchSize ?? 100;

    // 获取所有用户
    const totalCount = await this.userQueryRepository.count();
    const result: BatchSyncResult = {
      total: totalCount,
      processed: 0,
      results: [],
      errors: [],
    };

    let page = 1;
    let hasMore = true;

    while (hasMore) {
      const users = await this.userQueryRepository.findMany(
        {},
        { page, pageSize: batchSize },
      );

      if (users.items.length === 0) {
        hasMore = false;
        break;
      }

      for (const user of users.items) {
        try {
          const syncResult = await this.syncUserAutoTags(user.accountSequence);
          result.results.push(syncResult);
          result.processed++;
        } catch (error) {
          result.errors.push({
            accountSequence: user.accountSequence,
            error: error instanceof Error ? error.message : String(error),
          });
        }

        if (options?.onProgress) {
          options.onProgress(result.processed, totalCount);
        }
      }

      page++;
      hasMore = users.items.length === batchSize;
    }

    this.logger.log(
      `Auto tags sync completed: ${result.processed}/${result.total}, errors: ${result.errors.length}`,
    );

    return result;
  }

  /**
   * 清理过期标签
   */
  async cleanExpiredTags(): Promise<number> {
    const count = await this.tagRepository.cleanExpiredAssignments();
    this.logger.log(`Cleaned ${count} expired tag assignments`);
    return count;
  }

  /**
   * 获取用户的所有标签
   */
  async getUserTags(accountSequence: string): Promise<
    Array<{
      tagId: string;
      tagCode: string;
      tagName: string;
      value: string | null;
      isAuto: boolean;
      assignedAt: Date;
    }>
  > {
    const tags = await this.tagRepository.findUserTags(accountSequence);
    return tags.map((t) => ({
      tagId: t.tag.id,
      tagCode: t.tag.code,
      tagName: t.tag.name,
      value: t.assignment.value,
      isAuto: t.assignment.isAuto(),
      assignedAt: t.assignment.assignedAt,
    }));
  }

  /**
   * 检查用户是否有指定标签
   */
  async userHasTag(accountSequence: string, tagId: string): Promise<boolean> {
    return this.tagRepository.hasTag(accountSequence, tagId);
  }

  /**
   * 检查用户是否有任一标签
   */
  async userHasAnyTag(
    accountSequence: string,
    tagIds: string[],
  ): Promise<boolean> {
    return this.tagRepository.hasAnyTag(accountSequence, tagIds);
  }

  /**
   * 检查用户是否有所有标签
   */
  async userHasAllTags(
    accountSequence: string,
    tagIds: string[],
  ): Promise<boolean> {
    return this.tagRepository.hasAllTags(accountSequence, tagIds);
  }
}
