import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  Query,
  HttpCode,
  HttpStatus,
  Inject,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { v4 as uuidv4 } from 'uuid';
import {
  USER_TAG_REPOSITORY,
  UserTagRepository,
} from '../../domain/repositories/user-tag.repository';
import {
  TagCategoryEntity,
  UserTagEntity,
  TagType,
} from '../../domain/entities/user-tag.entity';
import { UserTaggingService } from '../../application/services/user-tagging.service';
import { RuleEngineService } from '../../application/services/rule-engine.service';
import {
  CreateTagCategoryDto,
  UpdateTagCategoryDto,
  CreateTagDto,
  UpdateTagDto,
  ListTagsDto,
  LinkRuleToTagDto,
  AssignTagToUserDto,
  BatchAssignTagDto,
  RemoveTagFromUserDto,
  GetUserTagsDto,
  GetTagUsersDto,
  SyncUserAutoTagsDto,
  BatchSyncAutoTagsDto,
  ListTagLogsDto,
} from '../dto/request/user-tag.dto';
import {
  TagCategoryResponseDto,
  TagResponseDto,
  TagListResponseDto,
  UserTagListResponseDto,
  TagUserListResponseDto,
  TagLogResponseDto,
  TagSyncResultResponseDto,
  BatchSyncResultResponseDto,
  BatchOperationResultDto,
} from '../dto/response/user-tag.dto';

/**
 * 标签管理控制器
 */
@Controller('admin/tags')
export class UserTagController {
  constructor(
    @Inject(USER_TAG_REPOSITORY)
    private readonly tagRepository: UserTagRepository,
    private readonly taggingService: UserTaggingService,
    private readonly ruleEngine: RuleEngineService,
  ) {}

  // =====================
  // 标签分类管理
  // =====================

  /**
   * 创建标签分类
   */
  @Post('categories')
  async createCategory(
    @Body() dto: CreateTagCategoryDto,
  ): Promise<TagCategoryResponseDto> {
    const existing = await this.tagRepository.findCategoryByCode(dto.code);
    if (existing) {
      throw new BadRequestException(`Category code already exists: ${dto.code}`);
    }

    const category = TagCategoryEntity.create({
      id: uuidv4(),
      code: dto.code,
      name: dto.name,
      description: dto.description,
      sortOrder: dto.sortOrder,
    });

    const saved = await this.tagRepository.saveCategory(category);
    return TagCategoryResponseDto.fromEntity(saved);
  }

  /**
   * 获取所有标签分类
   */
  @Get('categories')
  async listCategories(
    @Query('isEnabled') isEnabled?: string,
  ): Promise<TagCategoryResponseDto[]> {
    const categories = await this.tagRepository.findAllCategories({
      isEnabled: isEnabled === undefined ? undefined : isEnabled === 'true',
    });
    return categories.map(TagCategoryResponseDto.fromEntity);
  }

  /**
   * 获取标签分类详情
   */
  @Get('categories/:id')
  async getCategory(@Param('id') id: string): Promise<TagCategoryResponseDto> {
    const category = await this.tagRepository.findCategoryById(id);
    if (!category) {
      throw new NotFoundException(`Category not found: ${id}`);
    }
    return TagCategoryResponseDto.fromEntity(category);
  }

  /**
   * 更新标签分类
   */
  @Put('categories/:id')
  async updateCategory(
    @Param('id') id: string,
    @Body() dto: UpdateTagCategoryDto,
  ): Promise<TagCategoryResponseDto> {
    const existing = await this.tagRepository.findCategoryById(id);
    if (!existing) {
      throw new NotFoundException(`Category not found: ${id}`);
    }

    const updated = existing.update(dto);
    const saved = await this.tagRepository.saveCategory(updated);
    return TagCategoryResponseDto.fromEntity(saved);
  }

  /**
   * 删除标签分类
   */
  @Delete('categories/:id')
  @HttpCode(HttpStatus.NO_CONTENT)
  async deleteCategory(@Param('id') id: string): Promise<void> {
    await this.tagRepository.deleteCategory(id);
  }

  // =====================
  // 标签定义管理
  // =====================

  /**
   * 创建标签
   */
  @Post()
  async createTag(@Body() dto: CreateTagDto): Promise<TagResponseDto> {
    const existing = await this.tagRepository.findTagByCode(dto.code);
    if (existing) {
      throw new BadRequestException(`Tag code already exists: ${dto.code}`);
    }

    const tag = UserTagEntity.create({
      id: uuidv4(),
      code: dto.code,
      name: dto.name,
      categoryId: dto.categoryId,
      description: dto.description,
      color: dto.color,
      type: dto.type,
      valueType: dto.valueType,
      enumValues: dto.enumValues,
      isAdvertisable: dto.isAdvertisable,
      sortOrder: dto.sortOrder,
    });

    const saved = await this.tagRepository.saveTag(tag);
    return TagResponseDto.fromEntity(saved);
  }

  /**
   * 获取标签列表
   */
  @Get()
  async listTags(@Query() dto: ListTagsDto): Promise<TagListResponseDto> {
    const [items, total] = await Promise.all([
      this.tagRepository.findAllTags({
        categoryId: dto.categoryId,
        type: dto.type,
        isEnabled: dto.isEnabled,
        isAdvertisable: dto.isAdvertisable,
        limit: dto.limit,
        offset: dto.offset,
      }),
      this.tagRepository.countTags({
        categoryId: dto.categoryId,
        type: dto.type,
        isEnabled: dto.isEnabled,
      }),
    ]);

    return {
      items: items.map(TagResponseDto.fromEntity),
      total,
    };
  }

  /**
   * 获取标签详情
   */
  @Get(':id')
  async getTag(@Param('id') id: string): Promise<TagResponseDto> {
    const tag = await this.tagRepository.findTagById(id);
    if (!tag) {
      throw new NotFoundException(`Tag not found: ${id}`);
    }
    return TagResponseDto.fromEntity(tag);
  }

  /**
   * 更新标签
   */
  @Put(':id')
  async updateTag(
    @Param('id') id: string,
    @Body() dto: UpdateTagDto,
  ): Promise<TagResponseDto> {
    const existing = await this.tagRepository.findTagById(id);
    if (!existing) {
      throw new NotFoundException(`Tag not found: ${id}`);
    }

    const updated = existing.update(dto);
    const saved = await this.tagRepository.saveTag(updated);
    return TagResponseDto.fromEntity(saved);
  }

  /**
   * 删除标签
   */
  @Delete(':id')
  @HttpCode(HttpStatus.NO_CONTENT)
  async deleteTag(@Param('id') id: string): Promise<void> {
    const tag = await this.tagRepository.findTagById(id);
    if (!tag) {
      throw new NotFoundException(`Tag not found: ${id}`);
    }
    if (!tag.canDelete()) {
      throw new BadRequestException('System tags cannot be deleted');
    }
    await this.tagRepository.deleteTag(id);
  }

  /**
   * 关联规则到标签
   */
  @Post(':id/link-rule')
  async linkRule(
    @Param('id') id: string,
    @Body() dto: LinkRuleToTagDto,
  ): Promise<TagResponseDto> {
    const tag = await this.tagRepository.findTagById(id);
    if (!tag) {
      throw new NotFoundException(`Tag not found: ${id}`);
    }

    const linked = tag.linkRule(dto.ruleId);
    const saved = await this.tagRepository.saveTag(linked);
    return TagResponseDto.fromEntity(saved);
  }

  /**
   * 取消关联规则
   */
  @Post(':id/unlink-rule')
  async unlinkRule(@Param('id') id: string): Promise<TagResponseDto> {
    const tag = await this.tagRepository.findTagById(id);
    if (!tag) {
      throw new NotFoundException(`Tag not found: ${id}`);
    }

    const unlinked = tag.unlinkRule();
    const saved = await this.tagRepository.saveTag(unlinked);
    return TagResponseDto.fromEntity(saved);
  }

  /**
   * 预估标签用户数
   */
  @Get(':id/estimate-users')
  async estimateUsers(@Param('id') id: string): Promise<{ count: number }> {
    const tag = await this.tagRepository.findTagById(id);
    if (!tag) {
      throw new NotFoundException(`Tag not found: ${id}`);
    }

    // 直接使用计数方法
    const count = await this.tagRepository.countUsersByTagId(id);
    return { count };
  }

  // =====================
  // 用户标签操作
  // =====================

  /**
   * 给用户打标签
   */
  @Post('assign')
  @HttpCode(HttpStatus.OK)
  async assignTag(@Body() dto: AssignTagToUserDto): Promise<{ success: boolean }> {
    await this.taggingService.assignTag({
      accountSequence: dto.accountSequence,
      tagId: dto.tagId,
      value: dto.value,
      assignedBy: 'admin', // TODO: 从认证信息获取
      expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : undefined,
      reason: dto.reason,
    });
    return { success: true };
  }

  /**
   * 批量打标签
   */
  @Post('batch-assign')
  async batchAssign(
    @Body() dto: BatchAssignTagDto,
  ): Promise<BatchOperationResultDto> {
    return this.taggingService.batchAssignTag({
      accountSequences: dto.accountSequences,
      tagId: dto.tagId,
      value: dto.value,
      assignedBy: 'admin', // TODO: 从认证信息获取
      reason: dto.reason,
    });
  }

  /**
   * 移除用户标签
   */
  @Post('remove')
  @HttpCode(HttpStatus.OK)
  async removeTag(
    @Body() dto: RemoveTagFromUserDto,
  ): Promise<{ success: boolean }> {
    await this.taggingService.removeTag({
      accountSequence: dto.accountSequence,
      tagId: dto.tagId,
      operatorId: 'admin', // TODO: 从认证信息获取
      reason: dto.reason,
    });
    return { success: true };
  }

  /**
   * 获取用户的所有标签
   */
  @Get('user/:accountSequence')
  async getUserTags(
    @Param('accountSequence') accountSequence: string,
  ): Promise<UserTagListResponseDto> {
    const tags = await this.taggingService.getUserTags(accountSequence);
    return {
      accountSequence,
      tags: tags.map((t) => ({
        tagId: t.tagId,
        tagCode: t.tagCode,
        tagName: t.tagName,
        value: t.value,
        isAuto: t.isAuto,
        assignedAt: t.assignedAt.toISOString(),
      })),
    };
  }

  /**
   * 获取标签下的用户
   */
  @Get(':id/users')
  async getTagUsers(
    @Param('id') id: string,
    @Query() dto: GetTagUsersDto,
  ): Promise<TagUserListResponseDto> {
    const [assignments, total] = await Promise.all([
      this.tagRepository.findUsersByTagId(id, {
        value: dto.value,
        limit: dto.limit ?? 50,
        offset: dto.offset ?? 0,
      }),
      this.tagRepository.countUsersByTagId(id, dto.value),
    ]);

    return {
      tagId: id,
      users: assignments.map((a) => ({
        accountSequence: a.accountSequence,
        value: a.value,
        assignedAt: a.assignedAt.toISOString(),
        assignedBy: a.assignedBy,
        source: a.source,
      })),
      total,
    };
  }

  // =====================
  // 自动标签同步
  // =====================

  /**
   * 同步单个用户的自动标签
   */
  @Post('sync-user')
  async syncUserTags(
    @Body() dto: SyncUserAutoTagsDto,
  ): Promise<TagSyncResultResponseDto> {
    return this.taggingService.syncUserAutoTags(dto.accountSequence);
  }

  /**
   * 批量同步自动标签
   */
  @Post('batch-sync')
  async batchSyncTags(
    @Body() dto: BatchSyncAutoTagsDto,
  ): Promise<BatchSyncResultResponseDto> {
    return this.taggingService.batchSyncAutoTags(dto.accountSequences);
  }

  /**
   * 同步所有用户的自动标签
   */
  @Post('sync-all')
  async syncAllTags(): Promise<BatchSyncResultResponseDto> {
    return this.taggingService.syncAllAutoTags();
  }

  /**
   * 清理过期标签
   */
  @Post('clean-expired')
  async cleanExpiredTags(): Promise<{ count: number }> {
    const count = await this.taggingService.cleanExpiredTags();
    return { count };
  }

  // =====================
  // 标签变更日志
  // =====================

  /**
   * 查询标签变更日志
   */
  @Get('logs')
  async listLogs(@Query() dto: ListTagLogsDto): Promise<{
    items: TagLogResponseDto[];
    total: number;
  }> {
    const [logs, total] = await Promise.all([
      this.tagRepository.findLogs({
        accountSequence: dto.accountSequence,
        tagCode: dto.tagCode,
        startDate: dto.startDate ? new Date(dto.startDate) : undefined,
        endDate: dto.endDate ? new Date(dto.endDate) : undefined,
        limit: dto.limit ?? 50,
        offset: dto.offset ?? 0,
      }),
      this.tagRepository.countLogs({
        accountSequence: dto.accountSequence,
        tagCode: dto.tagCode,
        startDate: dto.startDate ? new Date(dto.startDate) : undefined,
        endDate: dto.endDate ? new Date(dto.endDate) : undefined,
      }),
    ]);

    return {
      items: logs.map(TagLogResponseDto.fromEntity),
      total,
    };
  }
}
