import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Post,
  Put,
  Query,
  UseGuards,
} from '@nestjs/common';
import { CommandBus, QueryBus } from '@nestjs/cqrs';
import {
  ApiTags,
  ApiOperation,
  ApiResponse,
  ApiBearerAuth,
  ApiParam,
} from '@nestjs/swagger';
import { type PlanTier } from '@prisma/client';
import { type JwtPayload, CurrentUser, JwtAuthGuard } from '@modules/auth';
import { CancelSubscriptionCommand } from '../../application/commands/cancel-subscription/cancel-subscription.command';
import { type CancelSubscriptionResult } from '../../application/commands/cancel-subscription/cancel-subscription.handler';
import { CreateSubscriptionCommand } from '../../application/commands/create-subscription/create-subscription.command';
import { type CreateSubscriptionResult } from '../../application/commands/create-subscription/create-subscription.handler';
import { MeterUsageCommand } from '../../application/commands/meter-usage/meter-usage.command';
import { type MeterUsageResult } from '../../application/commands/meter-usage/meter-usage.handler';
import { UpgradeSubscriptionCommand } from '../../application/commands/upgrade-subscription/upgrade-subscription.command';
import { type UpgradeSubscriptionResult } from '../../application/commands/upgrade-subscription/upgrade-subscription.handler';
import { type QuotaCheckResult } from '../../application/queries/check-quota/check-quota.handler';
import { CheckQuotaQuery } from '../../application/queries/check-quota/check-quota.query';
import { type BillingHistoryDto } from '../../application/queries/get-billing-history/get-billing-history.handler';
import { GetBillingHistoryQuery } from '../../application/queries/get-billing-history/get-billing-history.query';
import { type PlanDto } from '../../application/queries/get-plan/get-plan.handler';
import { GetPlanQuery } from '../../application/queries/get-plan/get-plan.query';
import { BillingHistoryParamsDto } from '../dto/billing-history.dto';
import { CancelSubscriptionDto } from '../dto/cancel-subscription.dto';
import { CreateSubscriptionDto } from '../dto/create-subscription.dto';
import { MeterUsageDto } from '../dto/meter-usage.dto';
import { UpgradeSubscriptionDto } from '../dto/upgrade-subscription.dto';

@ApiTags('subscriptions')
@Controller('subscriptions')
export class SubscriptionsController {
  constructor(
    private readonly commandBus: CommandBus,
    private readonly queryBus: QueryBus,
  ) {}

  // ── Plans (Public) ──

  @ApiOperation({ summary: 'List all subscription plans' })
  @ApiResponse({ status: 200, description: 'List of available plans' })
  @Get('plans')
  async listPlans(): Promise<PlanDto[]> {
    return this.queryBus.execute(new GetPlanQuery());
  }

  @ApiOperation({ summary: 'Get a subscription plan by tier' })
  @ApiParam({ name: 'tier', description: 'Plan tier identifier' })
  @ApiResponse({ status: 200, description: 'Plan details' })
  @ApiResponse({ status: 404, description: 'Plan not found' })
  @Get('plans/:tier')
  async getPlan(@Param('tier') tier: string): Promise<PlanDto> {
    return this.queryBus.execute(new GetPlanQuery(tier.toUpperCase() as PlanTier));
  }

  // ── Subscriptions (Authenticated) ──

  @ApiBearerAuth('JWT')
  @ApiOperation({ summary: 'Create a new subscription' })
  @ApiResponse({ status: 201, description: 'Subscription created' })
  @ApiResponse({ status: 400, description: 'Bad request' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @UseGuards(JwtAuthGuard)
  @Post()
  async createSubscription(
    @Body() dto: CreateSubscriptionDto,
    @CurrentUser() user: JwtPayload,
  ): Promise<CreateSubscriptionResult> {
    return this.commandBus.execute(
      new CreateSubscriptionCommand(user.sub, dto.planTier, dto.billingCycle),
    );
  }

  @ApiBearerAuth('JWT')
  @ApiOperation({ summary: 'Upgrade an existing subscription' })
  @ApiResponse({ status: 200, description: 'Subscription upgraded' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @UseGuards(JwtAuthGuard)
  @Put('upgrade')
  async upgradeSubscription(
    @Body() dto: UpgradeSubscriptionDto,
    @CurrentUser() user: JwtPayload,
  ): Promise<UpgradeSubscriptionResult> {
    return this.commandBus.execute(
      new UpgradeSubscriptionCommand(user.sub, dto.newPlanTier),
    );
  }

  @ApiBearerAuth('JWT')
  @ApiOperation({ summary: 'Cancel an active subscription' })
  @ApiResponse({ status: 200, description: 'Subscription cancelled' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @UseGuards(JwtAuthGuard)
  @Delete()
  async cancelSubscription(
    @Body() dto: CancelSubscriptionDto,
    @CurrentUser() user: JwtPayload,
  ): Promise<CancelSubscriptionResult> {
    return this.commandBus.execute(
      new CancelSubscriptionCommand(user.sub, dto.reason),
    );
  }

  // ── Usage / Quota ──

  @ApiBearerAuth('JWT')
  @ApiOperation({ summary: 'Record metered usage' })
  @ApiResponse({ status: 201, description: 'Usage recorded' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @UseGuards(JwtAuthGuard)
  @Post('usage')
  async meterUsage(
    @Body() dto: MeterUsageDto,
    @CurrentUser() user: JwtPayload,
  ): Promise<MeterUsageResult> {
    return this.commandBus.execute(
      new MeterUsageCommand(user.sub, dto.metric, dto.count),
    );
  }

  @ApiBearerAuth('JWT')
  @ApiOperation({ summary: 'Check remaining quota for a metric' })
  @ApiParam({
    name: 'metric',
    description:
      'Usage metric identifier. Known values map onto a plan field in METRIC_TO_PLAN_FIELD (see check-quota.handler.ts).',
    enum: [
      'listings_created',
      'searches_saved',
      'analytics_queries',
      'media_uploads',
      'featured_listings_promoted',
    ],
    example: 'listings_created',
  })
  @ApiResponse({ status: 200, description: 'Quota check result' })
  @ApiResponse({ status: 401, description: 'Chưa xác thực' })
  @ApiResponse({ status: 404, description: 'Không tìm thấy tài nguyên' })
  @UseGuards(JwtAuthGuard)
  @Get('quota/:metric')
  async checkQuota(
    @Param('metric') metric: string,
    @CurrentUser() user: JwtPayload,
  ): Promise<QuotaCheckResult> {
    return this.queryBus.execute(new CheckQuotaQuery(user.sub, metric));
  }

  // ── Billing ──

  @ApiBearerAuth('JWT')
  @ApiOperation({ summary: 'Get billing history' })
  @ApiResponse({ status: 200, description: 'Billing history records' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @UseGuards(JwtAuthGuard)
  @Get('billing')
  async getBillingHistory(
    @CurrentUser() user: JwtPayload,
    @Query() dto: BillingHistoryParamsDto,
  ): Promise<BillingHistoryDto> {
    return this.queryBus.execute(
      new GetBillingHistoryQuery(user.sub, dto.limit, dto.offset),
    );
  }
}
