import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  Query,
  UploadedFile,
  HttpCode,
  HttpStatus,
  UseInterceptors,
  ParseFilePipe,
  MaxFileSizeValidator,
  FileTypeValidator,
  NotFoundException,
  BadRequestException,
  Logger,
} from '@nestjs/common'
import { FileInterceptor } from '@nestjs/platform-express'
import { ApiTags, ApiOperation, ApiBearerAuth, ApiConsumes, ApiBody, ApiQuery } from '@nestjs/swagger'
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service'
import { FileStorageService } from '../../infrastructure/storage/file-storage.service'
import { AppAssetType } from '@prisma/client'

// 图片最大 10MB
const MAX_IMAGE_SIZE = 10 * 1024 * 1024

// 每种类型的数量上限
const ASSET_LIMITS: Record<AppAssetType, number> = {
  SPLASH: 10,
  GUIDE: 10,
}

// ===== Response DTO =====

interface AppAssetResponseDto {
  id: string
  type: AppAssetType
  sortOrder: number
  imageUrl: string
  title: string | null
  subtitle: string | null
  isEnabled: boolean
  createdAt: Date
  updatedAt: Date
}

// =============================================================================
// Admin Controller (需要认证)
// =============================================================================

@ApiTags('App Asset Management')
@Controller('admin/app-assets')
export class AdminAppAssetController {
  private readonly logger = new Logger(AdminAppAssetController.name)

  constructor(
    private readonly prisma: PrismaService,
    private readonly fileStorage: FileStorageService,
  ) {}

  @Get()
  @ApiBearerAuth()
  @ApiOperation({ summary: '查询应用资源列表' })
  @ApiQuery({ name: 'type', required: false, enum: AppAssetType })
  async list(@Query('type') type?: AppAssetType): Promise<AppAssetResponseDto[]> {
    const where = type ? { type } : {}
    const assets = await this.prisma.appAsset.findMany({
      where,
      orderBy: [{ type: 'asc' }, { sortOrder: 'asc' }],
    })
    return assets.map(this.toDto)
  }

  @Post('upload')
  @ApiBearerAuth()
  @UseInterceptors(FileInterceptor('file'))
  @ApiConsumes('multipart/form-data')
  @ApiOperation({ summary: '上传图片并创建/替换资源' })
  @ApiBody({
    schema: {
      type: 'object',
      required: ['file', 'type', 'sortOrder'],
      properties: {
        file: { type: 'string', format: 'binary' },
        type: { type: 'string', enum: ['SPLASH', 'GUIDE'] },
        sortOrder: { type: 'integer', minimum: 1 },
        title: { type: 'string' },
        subtitle: { type: 'string' },
      },
    },
  })
  async upload(
    @UploadedFile(
      new ParseFilePipe({
        validators: [
          new MaxFileSizeValidator({ maxSize: MAX_IMAGE_SIZE }),
          new FileTypeValidator({ fileType: /^image\/(jpeg|jpg|png|webp)$/ }),
        ],
        fileIsRequired: true,
      }),
    )
    file: Express.Multer.File,
    @Body('type') type: string,
    @Body('sortOrder') sortOrderStr: string,
    @Body('title') title?: string,
    @Body('subtitle') subtitle?: string,
  ): Promise<AppAssetResponseDto> {
    // 校验 type
    const assetType = type as AppAssetType
    if (!Object.values(AppAssetType).includes(assetType)) {
      throw new BadRequestException(`Invalid type: ${type}. Must be SPLASH or GUIDE`)
    }

    // 校验 sortOrder
    const sortOrder = parseInt(sortOrderStr, 10)
    if (isNaN(sortOrder) || sortOrder < 1) {
      throw new BadRequestException('sortOrder must be a positive integer')
    }

    const limit = ASSET_LIMITS[assetType]
    if (sortOrder > limit) {
      throw new BadRequestException(`sortOrder for ${assetType} must be between 1 and ${limit}`)
    }

    // 保存文件
    const uploadResult = await this.fileStorage.saveFile(
      file.buffer,
      file.originalname,
      'app-assets',
      `${assetType.toLowerCase()}-${sortOrder}`,
    )

    this.logger.log(
      `Uploaded app asset: type=${assetType}, sortOrder=${sortOrder}, url=${uploadResult.url}`,
    )

    // Upsert: 同 type+sortOrder 自动替换
    const asset = await this.prisma.appAsset.upsert({
      where: {
        type_sortOrder: { type: assetType, sortOrder },
      },
      create: {
        type: assetType,
        sortOrder,
        imageUrl: uploadResult.url,
        title: title || null,
        subtitle: subtitle || null,
        isEnabled: true,
      },
      update: {
        imageUrl: uploadResult.url,
        title: title !== undefined ? (title || null) : undefined,
        subtitle: subtitle !== undefined ? (subtitle || null) : undefined,
      },
    })

    return this.toDto(asset)
  }

  @Put(':id')
  @ApiBearerAuth()
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '更新资源元数据 (标题/副标题/启停)' })
  async update(
    @Param('id') id: string,
    @Body() body: { title?: string; subtitle?: string; isEnabled?: boolean },
  ): Promise<AppAssetResponseDto> {
    const existing = await this.prisma.appAsset.findUnique({ where: { id } })
    if (!existing) {
      throw new NotFoundException('App asset not found')
    }

    const data: Record<string, unknown> = {}
    if (body.title !== undefined) data.title = body.title || null
    if (body.subtitle !== undefined) data.subtitle = body.subtitle || null
    if (body.isEnabled !== undefined) data.isEnabled = body.isEnabled

    const updated = await this.prisma.appAsset.update({
      where: { id },
      data,
    })

    return this.toDto(updated)
  }

  @Delete(':id')
  @ApiBearerAuth()
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: '删除资源' })
  async delete(@Param('id') id: string): Promise<void> {
    const existing = await this.prisma.appAsset.findUnique({ where: { id } })
    if (!existing) {
      throw new NotFoundException('App asset not found')
    }
    await this.prisma.appAsset.delete({ where: { id } })
    this.logger.log(`Deleted app asset: id=${id}, type=${existing.type}, sortOrder=${existing.sortOrder}`)
  }

  private toDto(asset: {
    id: string
    type: AppAssetType
    sortOrder: number
    imageUrl: string
    title: string | null
    subtitle: string | null
    isEnabled: boolean
    createdAt: Date
    updatedAt: Date
  }): AppAssetResponseDto {
    return {
      id: asset.id,
      type: asset.type,
      sortOrder: asset.sortOrder,
      imageUrl: asset.imageUrl,
      title: asset.title,
      subtitle: asset.subtitle,
      isEnabled: asset.isEnabled,
      createdAt: asset.createdAt,
      updatedAt: asset.updatedAt,
    }
  }
}

// =============================================================================
// Public Controller (移动端调用，无需认证)
// =============================================================================

@ApiTags('App Assets (Public)')
@Controller('app-assets')
export class PublicAppAssetController {
  constructor(private readonly prisma: PrismaService) {}

  @Get()
  @ApiOperation({ summary: '获取已启用的应用资源 (移动端)' })
  @ApiQuery({ name: 'type', required: false, enum: AppAssetType })
  async list(@Query('type') type?: AppAssetType): Promise<AppAssetResponseDto[]> {
    const where: { isEnabled: boolean; type?: AppAssetType } = { isEnabled: true }
    if (type && Object.values(AppAssetType).includes(type)) {
      where.type = type
    }

    const assets = await this.prisma.appAsset.findMany({
      where,
      orderBy: [{ type: 'asc' }, { sortOrder: 'asc' }],
    })

    return assets.map((asset) => ({
      id: asset.id,
      type: asset.type,
      sortOrder: asset.sortOrder,
      imageUrl: asset.imageUrl,
      title: asset.title,
      subtitle: asset.subtitle,
      isEnabled: asset.isEnabled,
      createdAt: asset.createdAt,
      updatedAt: asset.updatedAt,
    }))
  }
}
