import {
  Controller,
  Get,
  Post,
  Put,
  Query,
  Param,
  Body,
  Headers,
  UnauthorizedException,
  Logger,
} from '@nestjs/common';
import { StatisticsAggregationService, DailyStatisticsDto } from '../../application/services/statistics-aggregation.service';
import { FinancialReportService, FinancialReportDto } from '../../application/services/financial-report.service';
import { AnalyticsSchedulerService } from '../../infrastructure/scheduling/analytics-scheduler.service';
import { AdminService } from '../../../application/services/admin.service';

@Controller('analytics')
export class AnalyticsController {
  private readonly logger = new Logger(AnalyticsController.name);

  constructor(
    private readonly statisticsService: StatisticsAggregationService,
    private readonly financialReportService: FinancialReportService,
    private readonly schedulerService: AnalyticsSchedulerService,
    private readonly adminService: AdminService,
  ) {}

  /**
   * Verify admin authorization
   */
  private async verifyAdmin(authorization: string): Promise<{ id: string; username: string }> {
    if (!authorization?.startsWith('Bearer ')) {
      throw new UnauthorizedException('Missing authorization token');
    }

    const token = authorization.substring(7);
    const result = await this.adminService.verifyToken(token);

    if (!result.valid || !result.admin) {
      throw new UnauthorizedException('Invalid or expired token');
    }

    return { id: result.admin.id, username: result.admin.username };
  }

  // ==================== Statistics Endpoints ====================

  /**
   * GET /analytics/statistics/daily
   * Get daily statistics with filters
   */
  @Get('statistics/daily')
  async getDailyStatistics(
    @Headers('authorization') auth: string,
    @Query('startDate') startDate: string,
    @Query('endDate') endDate: string,
    @Query('dimension') dimension?: string,
    @Query('dimensionValue') dimensionValue?: string,
  ): Promise<DailyStatisticsDto[]> {
    await this.verifyAdmin(auth);

    return this.statisticsService.getDailyStatistics({
      startDate,
      endDate,
      dimension,
      dimensionValue,
    });
  }

  /**
   * GET /analytics/statistics/today
   * Get real-time today statistics
   */
  @Get('statistics/today')
  async getTodayStatistics(
    @Headers('authorization') auth: string,
  ): Promise<DailyStatisticsDto | null> {
    await this.verifyAdmin(auth);
    return this.statisticsService.getTodayStatistics();
  }

  /**
   * GET /analytics/statistics/trend
   * Get trend data for charts
   */
  @Get('statistics/trend')
  async getStatisticsTrend(
    @Headers('authorization') auth: string,
    @Query('days') days = '7',
    @Query('metrics') metrics?: string,
  ): Promise<Record<string, { date: string; value: number }[]>> {
    await this.verifyAdmin(auth);

    const metricList = metrics
      ? metrics.split(',')
      : ['newUsers', 'newConversations', 'paidOrders', 'totalPaidAmount'];

    return this.statisticsService.getTrendData({
      days: parseInt(days, 10),
      metrics: metricList,
    });
  }

  /**
   * GET /analytics/statistics/by-channel
   * Get statistics breakdown by channel
   */
  @Get('statistics/by-channel')
  async getStatisticsByChannel(
    @Headers('authorization') auth: string,
    @Query('startDate') startDate: string,
    @Query('endDate') endDate: string,
  ): Promise<DailyStatisticsDto[]> {
    await this.verifyAdmin(auth);
    return this.statisticsService.getStatisticsByChannel(startDate, endDate);
  }

  /**
   * GET /analytics/statistics/by-category
   * Get statistics breakdown by category
   */
  @Get('statistics/by-category')
  async getStatisticsByCategory(
    @Headers('authorization') auth: string,
    @Query('startDate') startDate: string,
    @Query('endDate') endDate: string,
  ): Promise<DailyStatisticsDto[]> {
    await this.verifyAdmin(auth);
    return this.statisticsService.getStatisticsByCategory(startDate, endDate);
  }

  /**
   * POST /analytics/statistics/refresh
   * Manually trigger statistics refresh
   */
  @Post('statistics/refresh')
  async refreshStatistics(
    @Headers('authorization') auth: string,
    @Body() body: { date?: string },
  ): Promise<{ success: boolean; message: string }> {
    const admin = await this.verifyAdmin(auth);

    const date = body.date ? new Date(body.date) : new Date();
    this.logger.log(`Admin ${admin.username} triggered statistics refresh for ${date.toISOString()}`);

    await this.schedulerService.manualAggregateStats(date);

    return {
      success: true,
      message: `Statistics refreshed for ${date.toISOString().split('T')[0]}`,
    };
  }

  /**
   * POST /analytics/statistics/backfill
   * Backfill statistics for a date range
   */
  @Post('statistics/backfill')
  async backfillStatistics(
    @Headers('authorization') auth: string,
    @Body() body: { startDate: string; endDate: string },
  ): Promise<{ success: boolean; message: string }> {
    const admin = await this.verifyAdmin(auth);

    this.logger.log(`Admin ${admin.username} triggered backfill from ${body.startDate} to ${body.endDate}`);

    await this.schedulerService.backfillStatistics(
      new Date(body.startDate),
      new Date(body.endDate),
    );

    return {
      success: true,
      message: `Backfill completed from ${body.startDate} to ${body.endDate}`,
    };
  }

  // ==================== Financial Reports Endpoints ====================

  /**
   * GET /analytics/financial-reports
   * List financial reports
   */
  @Get('financial-reports')
  async listFinancialReports(
    @Headers('authorization') auth: string,
    @Query('year') year?: string,
    @Query('status') status?: string,
  ): Promise<FinancialReportDto[]> {
    await this.verifyAdmin(auth);

    return this.financialReportService.listReports({
      year: year ? parseInt(year, 10) : undefined,
      status,
    });
  }

  /**
   * GET /analytics/financial-reports/:month
   * Get specific month's financial report
   */
  @Get('financial-reports/:month')
  async getFinancialReport(
    @Headers('authorization') auth: string,
    @Param('month') month: string,
  ): Promise<FinancialReportDto> {
    await this.verifyAdmin(auth);
    return this.financialReportService.getReport(month);
  }

  /**
   * POST /analytics/financial-reports/generate
   * Manually generate financial report
   */
  @Post('financial-reports/generate')
  async generateFinancialReport(
    @Headers('authorization') auth: string,
    @Body() body: { month: string },
  ): Promise<{ success: boolean; message: string }> {
    const admin = await this.verifyAdmin(auth);

    this.logger.log(`Admin ${admin.username} triggered report generation for ${body.month}`);

    await this.schedulerService.manualGenerateReport(body.month);

    return {
      success: true,
      message: `Financial report generated for ${body.month}`,
    };
  }

  /**
   * PUT /analytics/financial-reports/:month/confirm
   * Confirm a financial report
   */
  @Put('financial-reports/:month/confirm')
  async confirmFinancialReport(
    @Headers('authorization') auth: string,
    @Param('month') month: string,
  ): Promise<FinancialReportDto> {
    const admin = await this.verifyAdmin(auth);

    this.logger.log(`Admin ${admin.username} confirming report for ${month}`);

    return this.financialReportService.confirmReport(month, admin.id);
  }

  /**
   * PUT /analytics/financial-reports/:month/lock
   * Lock a financial report
   */
  @Put('financial-reports/:month/lock')
  async lockFinancialReport(
    @Headers('authorization') auth: string,
    @Param('month') month: string,
  ): Promise<FinancialReportDto> {
    const admin = await this.verifyAdmin(auth);

    this.logger.log(`Admin ${admin.username} locking report for ${month}`);

    return this.financialReportService.lockReport(month);
  }

  /**
   * PUT /analytics/financial-reports/:month/notes
   * Update report notes
   */
  @Put('financial-reports/:month/notes')
  async updateReportNotes(
    @Headers('authorization') auth: string,
    @Param('month') month: string,
    @Body() body: { notes: string },
  ): Promise<FinancialReportDto> {
    await this.verifyAdmin(auth);
    return this.financialReportService.updateNotes(month, body.notes);
  }
}
