import {
  Body,
  Controller,
  Get,
  Param,
  Patch,
  Post,
  Query,
  UseGuards,
} from '@nestjs/common';
import { CommandBus, QueryBus } from '@nestjs/cqrs';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiQuery, ApiParam } from '@nestjs/swagger';
import { type JwtPayload, CurrentUser, Roles, JwtAuthGuard, RolesGuard } from '@modules/auth';
import { AdjustSubscriptionCommand } from '../../application/commands/adjust-subscription/adjust-subscription.command';
import { type AdjustSubscriptionResult } from '../../application/commands/adjust-subscription/adjust-subscription.handler';
import { BanUserCommand } from '../../application/commands/ban-user/ban-user.command';
import { type BanUserResult } from '../../application/commands/ban-user/ban-user.handler';
import { ProvisionDeveloperCommand } from '../../application/commands/provision-developer/provision-developer.command';
import { type ProvisionDeveloperResult } from '../../application/commands/provision-developer/provision-developer.handler';
import { ProvisionParkOperatorCommand } from '../../application/commands/provision-park-operator/provision-park-operator.command';
import { type ProvisionParkOperatorResult } from '../../application/commands/provision-park-operator/provision-park-operator.handler';
import { UpdateAiSettingsCommand } from '../../application/commands/update-ai-settings/update-ai-settings.command';
import { UpdateUserStatusCommand } from '../../application/commands/update-user-status/update-user-status.command';
import { type UpdateUserStatusResult } from '../../application/commands/update-user-status/update-user-status.handler';
import { GetAiSettingsQuery } from '../../application/queries/get-ai-settings/get-ai-settings.query';
import { type AiSettingsDto } from '../../application/queries/get-ai-settings/get-ai-settings.handler';
import { GetAuditLogsQuery } from '../../application/queries/get-audit-logs/get-audit-logs.query';
import { GetDashboardStatsQuery } from '../../application/queries/get-dashboard-stats/get-dashboard-stats.query';
import { GetRevenueStatsQuery } from '../../application/queries/get-revenue-stats/get-revenue-stats.query';
import { GetUserDetailQuery } from '../../application/queries/get-user-detail/get-user-detail.query';
import { GetUsersQuery } from '../../application/queries/get-users/get-users.query';
import {
  type DashboardStats,
  type RevenueStatsItem,
  type UserListResult,
  type UserDetail,
} from '../../domain/repositories/admin-query.repository';
import { type AuditLogListResult } from '../../domain/repositories/audit-log.repository';
import { AdjustSubscriptionDto } from '../dto/adjust-subscription.dto';
import { BanUserDto } from '../dto/ban-user.dto';
import { GetAuditLogsQueryDto } from '../dto/get-audit-logs-query.dto';
import { GetUsersQueryDto } from '../dto/get-users-query.dto';
import { ProvisionDeveloperDto } from '../dto/provision-developer.dto';
import { ProvisionParkOperatorDto } from '../dto/provision-park-operator.dto';
import { RevenueStatsDto } from '../dto/revenue-stats.dto';
import { UpdateAiSettingsDto } from '../dto/update-ai-settings.dto';
import { UpdateUserStatusDto } from '../dto/update-user-status.dto';

@ApiTags('admin')
@ApiBearerAuth('JWT')
@Controller('admin')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('ADMIN')
export class AdminController {
  constructor(
    private readonly commandBus: CommandBus,
    private readonly queryBus: QueryBus,
  ) {}

  // ── User Management ──

  @Get('users')
  @ApiOperation({ summary: 'List users with optional filters' })
  @ApiResponse({ status: 200, description: 'User list retrieved successfully' })
  @ApiResponse({ status: 401, description: 'Unauthorized – missing or invalid JWT' })
  @ApiResponse({ status: 403, description: 'Forbidden – requires ADMIN role' })
  async getUsers(
    @Query() query: GetUsersQueryDto,
  ): Promise<UserListResult> {
    return this.queryBus.execute(
      new GetUsersQuery(
        query.page ?? 1,
        query.limit ?? 20,
        query.role,
        query.isActive,
        query.search,
      ),
    );
  }

  @Get('users/:id')
  @ApiOperation({ summary: 'Get user details by ID' })
  @ApiParam({ name: 'id', description: 'User ID' })
  @ApiResponse({ status: 200, description: 'User detail retrieved successfully' })
  @ApiResponse({ status: 401, description: 'Unauthorized – missing or invalid JWT' })
  @ApiResponse({ status: 403, description: 'Forbidden – requires ADMIN role' })
  async getUserDetail(
    @Param('id') id: string,
  ): Promise<UserDetail> {
    return this.queryBus.execute(new GetUserDetailQuery(id));
  }

  @Patch('users/status')
  @ApiOperation({ summary: 'Update user active status' })
  @ApiResponse({ status: 200, description: 'User status updated successfully' })
  @ApiResponse({ status: 401, description: 'Unauthorized – missing or invalid JWT' })
  @ApiResponse({ status: 403, description: 'Forbidden – requires ADMIN role' })
  async updateUserStatus(
    @Body() dto: UpdateUserStatusDto,
    @CurrentUser() user: JwtPayload,
  ): Promise<UpdateUserStatusResult> {
    return this.commandBus.execute(
      new UpdateUserStatusCommand(dto.userId, user.sub, dto.isActive, dto.reason),
    );
  }

  @Post('users/ban')
  @ApiOperation({ summary: 'Ban or unban a user' })
  @ApiResponse({ status: 201, description: 'User ban status updated successfully' })
  @ApiResponse({ status: 401, description: 'Unauthorized – missing or invalid JWT' })
  @ApiResponse({ status: 403, description: 'Forbidden – requires ADMIN role' })
  async banUser(
    @Body() dto: BanUserDto,
    @CurrentUser() user: JwtPayload,
  ): Promise<BanUserResult> {
    return this.commandBus.execute(
      new BanUserCommand(dto.userId, user.sub, dto.reason, dto.unban ?? false),
    );
  }

  // ── Subscription Management ──

  @Post('subscriptions/adjust')
  @ApiOperation({ summary: 'Adjust user subscription plan' })
  @ApiResponse({ status: 201, description: 'Subscription adjusted successfully' })
  @ApiResponse({ status: 401, description: 'Unauthorized – missing or invalid JWT' })
  @ApiResponse({ status: 403, description: 'Forbidden – requires ADMIN role' })
  async adjustSubscription(
    @Body() dto: AdjustSubscriptionDto,
    @CurrentUser() user: JwtPayload,
  ): Promise<AdjustSubscriptionResult> {
    return this.commandBus.execute(
      new AdjustSubscriptionCommand(dto.userId, user.sub, dto.newPlanTier, dto.reason),
    );
  }

  // ── Dashboard ──

  @Get('dashboard')
  @ApiOperation({ summary: 'Get admin dashboard statistics' })
  @ApiResponse({
    status: 200,
    description: 'Dashboard stats retrieved successfully',
    schema: {
      example: {
        totalUsers: 12840,
        totalListings: 5432,
        activeListings: 4021,
        pendingModerationCount: 38,
        totalAgents: 612,
        verifiedAgents: 417,
        totalTransactions: 980,
        newUsersLast30Days: 246,
        newListingsLast30Days: 183,
      },
    },
  })
  @ApiResponse({ status: 401, description: 'Unauthorized – missing or invalid JWT' })
  @ApiResponse({ status: 403, description: 'Forbidden – requires ADMIN role' })
  async getDashboardStats(): Promise<DashboardStats> {
    return this.queryBus.execute(new GetDashboardStatsQuery());
  }

  @Get('revenue')
  @ApiOperation({ summary: 'Get revenue statistics' })
  @ApiQuery({ name: 'startDate', required: true, type: String, description: 'Start date (ISO 8601)' })
  @ApiQuery({ name: 'endDate', required: true, type: String, description: 'End date (ISO 8601)' })
  @ApiQuery({ name: 'groupBy', required: false, enum: ['day', 'month'], description: 'Group results by day or month (default month)' })
  @ApiResponse({ status: 200, description: 'Revenue stats retrieved successfully' })
  @ApiResponse({ status: 401, description: 'Unauthorized – missing or invalid JWT' })
  @ApiResponse({ status: 403, description: 'Forbidden – requires ADMIN role' })
  async getRevenueStats(
    @Query() dto: RevenueStatsDto,
  ): Promise<RevenueStatsItem[]> {
    return this.queryBus.execute(
      new GetRevenueStatsQuery(
        new Date(dto.startDate),
        new Date(dto.endDate),
        dto.groupBy ?? 'month',
      ),
    );
  }

  // ── AI Settings ──

  @Get('settings/ai')
  @ApiOperation({ summary: 'Get AI provider (Claude) settings' })
  @ApiResponse({ status: 200, description: 'AI settings retrieved successfully' })
  @ApiResponse({ status: 401, description: 'Unauthorized – missing or invalid JWT' })
  @ApiResponse({ status: 403, description: 'Forbidden – requires ADMIN role' })
  async getAiSettings(): Promise<AiSettingsDto> {
    return this.queryBus.execute(new GetAiSettingsQuery());
  }

  @Patch('settings/ai')
  @ApiOperation({ summary: 'Update AI provider (Claude) settings' })
  @ApiResponse({ status: 200, description: 'AI settings updated successfully' })
  @ApiResponse({ status: 401, description: 'Unauthorized – missing or invalid JWT' })
  @ApiResponse({ status: 403, description: 'Forbidden – requires ADMIN role' })
  async updateAiSettings(
    @Body() dto: UpdateAiSettingsDto,
    @CurrentUser() user: JwtPayload,
  ): Promise<AiSettingsDto> {
    return this.commandBus.execute(
      new UpdateAiSettingsCommand(user.sub, dto.apiUrl, dto.apiKey, dto.model),
    );
  }

  // ── B2B Account Provisioning ──────────────────────────────────────

  @Post('accounts/developers')
  @ApiOperation({
    summary: 'Tạo tài khoản CĐT (DEVELOPER) — admin only',
    description:
      'Tạo mới một user với role=DEVELOPER và tuỳ chọn gán quyền sở hữu các ProjectDevelopment hiện có. Dự án đã có owner khác sẽ bị từ chối.',
  })
  @ApiResponse({ status: 201, description: 'Tạo tài khoản CĐT thành công' })
  @ApiResponse({ status: 400, description: 'Dữ liệu không hợp lệ' })
  @ApiResponse({ status: 401, description: 'Chưa xác thực' })
  @ApiResponse({ status: 403, description: 'Yêu cầu role ADMIN' })
  @ApiResponse({ status: 409, description: 'Số điện thoại/email đã tồn tại hoặc dự án đã có CĐT khác' })
  async provisionDeveloper(
    @Body() dto: ProvisionDeveloperDto,
  ): Promise<ProvisionDeveloperResult> {
    return this.commandBus.execute(
      new ProvisionDeveloperCommand(
        dto.phone,
        dto.password,
        dto.fullName,
        dto.email ?? null,
        dto.projectIds ?? [],
      ),
    );
  }

  @Post('accounts/park-operators')
  @ApiOperation({
    summary: 'Tạo tài khoản vận hành KCN (PARK_OPERATOR) — admin only',
    description:
      'Tạo mới một user với role=PARK_OPERATOR và tuỳ chọn gán quyền vận hành các IndustrialPark hiện có.',
  })
  @ApiResponse({ status: 201, description: 'Tạo tài khoản PARK_OPERATOR thành công' })
  @ApiResponse({ status: 400, description: 'Dữ liệu không hợp lệ' })
  @ApiResponse({ status: 401, description: 'Chưa xác thực' })
  @ApiResponse({ status: 403, description: 'Yêu cầu role ADMIN' })
  @ApiResponse({ status: 409, description: 'Số điện thoại/email đã tồn tại hoặc KCN đã có đơn vị khác' })
  async provisionParkOperator(
    @Body() dto: ProvisionParkOperatorDto,
  ): Promise<ProvisionParkOperatorResult> {
    return this.commandBus.execute(
      new ProvisionParkOperatorCommand(
        dto.phone,
        dto.password,
        dto.fullName,
        dto.email ?? null,
        dto.parkIds ?? [],
      ),
    );
  }

  // ── Audit Logs ──

  @Get('audit-logs')
  @ApiOperation({ summary: 'Get admin audit logs' })
  @ApiResponse({ status: 200, description: 'Audit logs retrieved successfully' })
  @ApiResponse({ status: 401, description: 'Unauthorized – missing or invalid JWT' })
  @ApiResponse({ status: 403, description: 'Forbidden – requires ADMIN role' })
  async getAuditLogs(
    @Query() query: GetAuditLogsQueryDto,
  ): Promise<AuditLogListResult> {
    return this.queryBus.execute(
      new GetAuditLogsQuery(
        query.page ?? 1,
        query.limit ?? 20,
        query.action,
        query.actorId,
        query.targetId,
        query.targetType,
        query.startDate ? new Date(query.startDate) : undefined,
        query.endDate ? new Date(query.endDate) : undefined,
      ),
    );
  }
}
