import { Injectable, Inject, Logger } from '@nestjs/common';
import { v4 as uuidv4 } from 'uuid';
import {
  AUDIENCE_SEGMENT_REPOSITORY,
  AudienceSegmentRepository,
} from '../../domain/repositories/audience-segment.repository';
import {
  USER_TAG_REPOSITORY,
  UserTagRepository,
} from '../../domain/repositories/user-tag.repository';
import {
  USER_QUERY_REPOSITORY,
  IUserQueryRepository,
  UserQueryItem,
} from '../../domain/repositories/user-query.repository';
import {
  AudienceSegmentEntity,
  SegmentConditionGroup,
  SegmentCondition,
  SegmentUsageType,
} from '../../domain/entities/audience-segment.entity';

/**
 * 人群包匹配结果
 */
export interface SegmentMatchResult {
  segmentId: string;
  segmentName: string;
  matched: boolean;
}

/**
 * 人群包服务
 * 负责人群包的创建、评估和用户匹配
 */
@Injectable()
export class AudienceSegmentService {
  private readonly logger = new Logger(AudienceSegmentService.name);

  constructor(
    @Inject(AUDIENCE_SEGMENT_REPOSITORY)
    private readonly segmentRepository: AudienceSegmentRepository,
    @Inject(USER_TAG_REPOSITORY)
    private readonly tagRepository: UserTagRepository,
    @Inject(USER_QUERY_REPOSITORY)
    private readonly userQueryRepository: IUserQueryRepository,
  ) {}

  /**
   * 创建人群包
   */
  async createSegment(params: {
    name: string;
    description?: string;
    conditions: SegmentConditionGroup;
    usageType?: SegmentUsageType;
    createdBy: string;
  }): Promise<AudienceSegmentEntity> {
    // 验证条件格式
    if (!AudienceSegmentEntity.validateConditions(params.conditions)) {
      throw new Error('Invalid segment conditions format');
    }

    const segment = AudienceSegmentEntity.create({
      id: uuidv4(),
      name: params.name,
      description: params.description,
      conditions: params.conditions,
      usageType: params.usageType,
      createdBy: params.createdBy,
    });

    const saved = await this.segmentRepository.save(segment);

    // 异步计算预估用户数
    this.calculateEstimatedUsers(saved.id).catch((err) => {
      this.logger.error(`Failed to calculate estimated users: ${err.message}`);
    });

    return saved;
  }

  /**
   * 更新人群包
   */
  async updateSegment(
    id: string,
    params: {
      name?: string;
      description?: string | null;
      conditions?: SegmentConditionGroup;
      usageType?: SegmentUsageType;
      isEnabled?: boolean;
    },
  ): Promise<AudienceSegmentEntity> {
    const segment = await this.segmentRepository.findById(id);
    if (!segment) {
      throw new Error(`Segment not found: ${id}`);
    }

    if (params.conditions) {
      if (!AudienceSegmentEntity.validateConditions(params.conditions)) {
        throw new Error('Invalid segment conditions format');
      }
    }

    const updated = segment.update(params);
    const saved = await this.segmentRepository.save(updated);

    // 如果条件变化，重新计算预估用户数
    if (params.conditions) {
      this.calculateEstimatedUsers(saved.id).catch((err) => {
        this.logger.error(`Failed to calculate estimated users: ${err.message}`);
      });
    }

    return saved;
  }

  /**
   * 删除人群包
   */
  async deleteSegment(id: string): Promise<void> {
    await this.segmentRepository.delete(id);
  }

  /**
   * 获取人群包详情
   */
  async getSegment(id: string): Promise<AudienceSegmentEntity | null> {
    return this.segmentRepository.findById(id);
  }

  /**
   * 获取人群包列表
   */
  async listSegments(params?: {
    usageType?: SegmentUsageType;
    isEnabled?: boolean;
    limit?: number;
    offset?: number;
  }): Promise<{ items: AudienceSegmentEntity[]; total: number }> {
    const [items, total] = await Promise.all([
      this.segmentRepository.findAll(params),
      this.segmentRepository.count({
        usageType: params?.usageType,
        isEnabled: params?.isEnabled,
      }),
    ]);

    return { items, total };
  }

  /**
   * 评估用户是否匹配人群包
   */
  async evaluateUser(
    accountSequence: string,
    segmentId: string,
  ): Promise<boolean> {
    const segment = await this.segmentRepository.findById(segmentId);
    if (!segment || !segment.isEnabled) {
      return false;
    }

    const user =
      await this.userQueryRepository.findByAccountSequence(accountSequence);
    if (!user) {
      return false;
    }

    const userTagIds = await this.tagRepository.findUserTagIds(accountSequence);

    return this.evaluateConditions(user, userTagIds, segment.conditions);
  }

  /**
   * 评估用户匹配的所有人群包
   */
  async evaluateUserSegments(
    accountSequence: string,
    usageType?: SegmentUsageType,
  ): Promise<SegmentMatchResult[]> {
    const segments = await this.segmentRepository.findAll({
      usageType,
      isEnabled: true,
    });

    const user =
      await this.userQueryRepository.findByAccountSequence(accountSequence);
    if (!user) {
      return segments.map((s) => ({
        segmentId: s.id,
        segmentName: s.name,
        matched: false,
      }));
    }

    const userTagIds = await this.tagRepository.findUserTagIds(accountSequence);

    return segments.map((segment) => ({
      segmentId: segment.id,
      segmentName: segment.name,
      matched: this.evaluateConditions(user, userTagIds, segment.conditions),
    }));
  }

  /**
   * 查找匹配人群包的所有用户
   */
  async findMatchingUsers(
    segmentId: string,
    options?: { limit?: number; offset?: number },
  ): Promise<{ accountSequences: string[]; total: number }> {
    const segment = await this.segmentRepository.findById(segmentId);
    if (!segment) {
      return { accountSequences: [], total: 0 };
    }

    // 获取所有用户并评估
    // TODO: 优化为数据库层面的筛选
    const allUsers = await this.userQueryRepository.findMany(
      {},
      { page: 1, pageSize: 10000 },
    );

    const matchingSequences: string[] = [];

    for (const user of allUsers.items) {
      const userTagIds = await this.tagRepository.findUserTagIds(
        user.accountSequence,
      );
      if (this.evaluateConditions(user, userTagIds, segment.conditions)) {
        matchingSequences.push(user.accountSequence);
      }
    }

    const total = matchingSequences.length;
    const offset = options?.offset ?? 0;
    const limit = options?.limit ?? total;

    return {
      accountSequences: matchingSequences.slice(offset, offset + limit),
      total,
    };
  }

  /**
   * 计算人群包预估用户数
   */
  async calculateEstimatedUsers(segmentId: string): Promise<number> {
    const { total } = await this.findMatchingUsers(segmentId);
    await this.segmentRepository.updateEstimatedUsers(segmentId, total);
    return total;
  }

  /**
   * 批量更新所有人群包的预估用户数
   */
  async recalculateAllEstimatedUsers(): Promise<void> {
    const segments = await this.segmentRepository.findAll({ isEnabled: true });

    for (const segment of segments) {
      try {
        await this.calculateEstimatedUsers(segment.id);
      } catch (err) {
        this.logger.error(
          `Failed to calculate estimated users for segment ${segment.id}: ${err}`,
        );
      }
    }
  }

  /**
   * 评估条件组
   */
  private evaluateConditions(
    user: UserQueryItem,
    userTagIds: string[],
    group: SegmentConditionGroup,
  ): boolean {
    if (group.type === 'AND') {
      return group.conditions.every((condition) => {
        if (this.isConditionGroup(condition)) {
          return this.evaluateConditions(
            user,
            userTagIds,
            condition as SegmentConditionGroup,
          );
        }
        return this.evaluateSingleCondition(
          user,
          userTagIds,
          condition as SegmentCondition,
        );
      });
    } else {
      return group.conditions.some((condition) => {
        if (this.isConditionGroup(condition)) {
          return this.evaluateConditions(
            user,
            userTagIds,
            condition as SegmentConditionGroup,
          );
        }
        return this.evaluateSingleCondition(
          user,
          userTagIds,
          condition as SegmentCondition,
        );
      });
    }
  }

  /**
   * 判断是否为条件组
   */
  private isConditionGroup(
    condition: SegmentCondition | SegmentConditionGroup,
  ): boolean {
    return (
      'type' in condition &&
      ['AND', 'OR'].includes(condition.type as string) &&
      'conditions' in condition
    );
  }

  /**
   * 评估单个条件
   */
  private evaluateSingleCondition(
    user: UserQueryItem,
    userTagIds: string[],
    condition: SegmentCondition,
  ): boolean {
    switch (condition.type) {
      case 'tag':
        return this.evaluateTagCondition(userTagIds, condition);
      case 'feature':
        return this.evaluateFeatureCondition(user, condition);
      case 'profile':
        return this.evaluateProfileCondition(user, condition);
      default:
        return false;
    }
  }

  /**
   * 评估标签条件
   */
  private evaluateTagCondition(
    userTagIds: string[],
    condition: SegmentCondition,
  ): boolean {
    const tagCode = condition.field;

    // TODO: 需要根据 tagCode 查找对应的 tagId
    // 目前简化处理，假设 field 就是 tagId
    const hasTag = userTagIds.includes(tagCode);

    switch (condition.operator) {
      case 'eq':
        return hasTag === (condition.value === true || condition.value === 'true');
      case 'neq':
        return hasTag !== (condition.value === true || condition.value === 'true');
      case 'in':
        if (Array.isArray(condition.value)) {
          return condition.value.some((v) => userTagIds.includes(v as string));
        }
        return false;
      case 'not_in':
        if (Array.isArray(condition.value)) {
          return !condition.value.some((v) => userTagIds.includes(v as string));
        }
        return true;
      default:
        return hasTag;
    }
  }

  /**
   * 评估特征条件 (RFM等)
   */
  private evaluateFeatureCondition(
    _user: UserQueryItem,
    _condition: SegmentCondition,
  ): boolean {
    // TODO: 需要从 UserFeature 表获取特征数据
    // 目前返回 false，待实现
    return false;
  }

  /**
   * 评估用户资料条件
   */
  private evaluateProfileCondition(
    user: UserQueryItem,
    condition: SegmentCondition,
  ): boolean {
    const value = this.getProfileValue(user, condition.field);
    return this.compareValues(value, condition.operator, condition.value);
  }

  /**
   * 获取用户资料字段值
   */
  private getProfileValue(
    user: UserQueryItem,
    field: string,
  ): number | string | Date | null {
    switch (field) {
      case 'registeredAt':
        return user.registeredAt;
      case 'personalAdoptionCount':
        return user.personalAdoptionCount;
      case 'teamAdoptionCount':
        return user.teamAdoptionCount;
      case 'teamAddressCount':
        return user.teamAddressCount;
      case 'provinceAdoptionCount':
        return user.provinceAdoptionCount;
      case 'cityAdoptionCount':
        return user.cityAdoptionCount;
      case 'kycStatus':
        return user.kycStatus;
      case 'lastActiveAt':
        return user.lastActiveAt;
      case 'status':
        return user.status;
      default:
        return null;
    }
  }

  /**
   * 比较值
   */
  private compareValues(
    actual: number | string | Date | null,
    operator: string,
    expected: unknown,
  ): boolean {
    if (actual === null) return false;

    switch (operator) {
      case 'eq':
        return actual === expected;
      case 'neq':
        return actual !== expected;
      case 'gt':
        return typeof actual === 'number' && actual > Number(expected);
      case 'gte':
        return typeof actual === 'number' && actual >= Number(expected);
      case 'lt':
        return typeof actual === 'number' && actual < Number(expected);
      case 'lte':
        return typeof actual === 'number' && actual <= Number(expected);
      case 'in':
        return Array.isArray(expected) && expected.includes(String(actual));
      case 'not_in':
        return Array.isArray(expected) && !expected.includes(String(actual));
      case 'contains':
        return (
          typeof actual === 'string' &&
          typeof expected === 'string' &&
          actual.includes(expected)
        );
      case 'starts_with':
        return (
          typeof actual === 'string' &&
          typeof expected === 'string' &&
          actual.startsWith(expected)
        );
      case 'ends_with':
        return (
          typeof actual === 'string' &&
          typeof expected === 'string' &&
          actual.endsWith(expected)
        );
      default:
        return false;
    }
  }
}
