import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  Query,
  HttpCode,
  HttpStatus,
  Inject,
  NotFoundException,
} from '@nestjs/common';
import { v4 as uuidv4 } from 'uuid';
import {
  NOTIFICATION_REPOSITORY,
  NotificationRepository,
} from '../../domain/repositories/notification.repository';
import {
  NotificationEntity,
  NotificationTarget,
  TargetType,
} from '../../domain/entities/notification.entity';
import {
  CreateNotificationDto,
  UpdateNotificationDto,
  ListNotificationsDto,
  UserNotificationsDto,
  MarkReadDto,
} from '../dto/request/notification.dto';
import {
  NotificationResponseDto,
  UserNotificationResponseDto,
  UnreadCountResponseDto,
  NotificationListResponseDto,
} from '../dto/response/notification.dto';

/**
 * 管理端通知控制器
 */
@Controller('admin/notifications')
export class AdminNotificationController {
  constructor(
    @Inject(NOTIFICATION_REPOSITORY)
    private readonly notificationRepo: NotificationRepository,
  ) {}

  /**
   * 创建通知
   */
  @Post()
  async create(@Body() dto: CreateNotificationDto): Promise<NotificationResponseDto> {
    // 构建目标配置
    let targetConfig: NotificationTarget | null = null;
    const targetType = dto.targetType ?? TargetType.ALL;

    if (dto.targetConfig || targetType !== TargetType.ALL) {
      targetConfig = {
        type: targetType,
        tagIds: dto.targetConfig?.tagIds,
        segmentId: dto.targetConfig?.segmentId,
        accountSequences: dto.targetConfig?.accountSequences,
      };
    }

    const notification = NotificationEntity.create({
      id: uuidv4(),
      title: dto.title,
      content: dto.content,
      type: dto.type,
      priority: dto.priority,
      targetType,
      targetConfig,
      imageUrl: dto.imageUrl,
      linkUrl: dto.linkUrl,
      requiresForceRead: dto.requiresForceRead,
      publishedAt: dto.publishedAt ? new Date(dto.publishedAt) : null,
      expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : null,
      createdBy: 'admin', // TODO: 从认证信息获取
    });

    const saved = await this.notificationRepo.save(notification);
    return NotificationResponseDto.fromEntity(saved);
  }

  /**
   * 获取通知详情
   */
  @Get(':id')
  async findOne(@Param('id') id: string): Promise<NotificationResponseDto> {
    const notification = await this.notificationRepo.findById(id);
    if (!notification) {
      throw new NotFoundException('Notification not found');
    }
    return NotificationResponseDto.fromEntity(notification);
  }

  /**
   * 获取通知列表（管理端）
   */
  @Get()
  async findAll(@Query() dto: ListNotificationsDto): Promise<NotificationResponseDto[]> {
    const notifications = await this.notificationRepo.findAll({
      type: dto.type,
      limit: dto.limit,
      offset: dto.offset,
    });
    return notifications.map(NotificationResponseDto.fromEntity);
  }

  /**
   * 更新通知
   */
  @Put(':id')
  async update(
    @Param('id') id: string,
    @Body() dto: UpdateNotificationDto,
  ): Promise<NotificationResponseDto> {
    const existing = await this.notificationRepo.findById(id);
    if (!existing) {
      throw new NotFoundException('Notification not found');
    }

    // 构建目标配置
    let targetConfig: NotificationTarget | null | undefined = undefined;
    if (dto.targetConfig !== undefined || dto.targetType !== undefined) {
      const targetType = dto.targetType ?? existing.targetType;
      if (dto.targetConfig || targetType !== TargetType.ALL) {
        targetConfig = {
          type: targetType,
          tagIds: dto.targetConfig?.tagIds ?? existing.targetConfig?.tagIds,
          segmentId: dto.targetConfig?.segmentId ?? existing.targetConfig?.segmentId,
          accountSequences:
            dto.targetConfig?.accountSequences ??
            existing.targetConfig?.accountSequences,
        };
      } else {
        targetConfig = null;
      }
    }

    const updated = existing.update({
      title: dto.title,
      content: dto.content,
      type: dto.type,
      priority: dto.priority,
      targetType: dto.targetType,
      targetConfig,
      imageUrl: dto.imageUrl,
      linkUrl: dto.linkUrl,
      isEnabled: dto.isEnabled,
      requiresForceRead: dto.requiresForceRead,
      publishedAt: dto.publishedAt !== undefined
        ? dto.publishedAt
          ? new Date(dto.publishedAt)
          : null
        : undefined,
      expiresAt: dto.expiresAt !== undefined
        ? dto.expiresAt
          ? new Date(dto.expiresAt)
          : null
        : undefined,
    });

    const saved = await this.notificationRepo.save(updated);
    return NotificationResponseDto.fromEntity(saved);
  }

  /**
   * 删除通知
   */
  @Delete(':id')
  @HttpCode(HttpStatus.NO_CONTENT)
  async delete(@Param('id') id: string): Promise<void> {
    await this.notificationRepo.delete(id);
  }
}

/**
 * 移动端通知控制器
 */
@Controller('mobile/notifications')
export class MobileNotificationController {
  constructor(
    @Inject(NOTIFICATION_REPOSITORY)
    private readonly notificationRepo: NotificationRepository,
  ) {}

  /**
   * 获取用户的通知列表
   */
  @Get()
  async getNotifications(
    @Query() dto: UserNotificationsDto,
  ): Promise<NotificationListResponseDto> {
    const [notifications, unreadCount] = await Promise.all([
      this.notificationRepo.findNotificationsForUser({
        userSerialNum: dto.userSerialNum,
        type: dto.type,
        limit: dto.limit ?? 50,
        offset: dto.offset ?? 0,
      }),
      this.notificationRepo.countUnreadForUser(dto.userSerialNum),
    ]);

    return {
      notifications: notifications.map(UserNotificationResponseDto.fromEntity),
      total: notifications.length,
      unreadCount,
    };
  }

  /**
   * 获取未读通知数量
   */
  @Get('unread-count')
  async getUnreadCount(
    @Query('userSerialNum') userSerialNum: string,
  ): Promise<UnreadCountResponseDto> {
    const unreadCount = await this.notificationRepo.countUnreadForUser(userSerialNum);
    return { unreadCount };
  }

  /**
   * 标记通知为已读
   */
  @Post('mark-read')
  @HttpCode(HttpStatus.OK)
  async markRead(@Body() dto: MarkReadDto): Promise<{ success: boolean }> {
    if (dto.notificationId) {
      await this.notificationRepo.markAsRead(dto.notificationId, dto.userSerialNum);
    } else {
      await this.notificationRepo.markAllAsRead(dto.userSerialNum);
    }
    return { success: true };
  }
}
