import {
  Controller,
  Get,
  Post,
  Body,
  Query,
  Param,
  Req,
  Res,
  Header,
  UseGuards,
  BadRequestException,
} from '@nestjs/common';
import { Response } from 'express';
import { PatternAnalysisService } from './pattern-analysis.service';
import { PredictionService } from './prediction.service';
import { ReportService } from './report.service';
import { ComparisonService } from './comparison.service';
import { AdvancedPatternService } from './advanced-pattern.service';
import { GrowthPercentileService } from './growth-percentile.service';
import { ComparisonMetric } from './dto/comparison.dto';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { CurrentUser } from '../auth/decorators/current-user.decorator';
import { ActivityType } from '../../database/entities/activity.entity';

@Controller('api/v1/analytics')
@UseGuards(JwtAuthGuard)
export class AnalyticsController {
  constructor(
    private readonly patternAnalysisService: PatternAnalysisService,
    private readonly predictionService: PredictionService,
    private readonly reportService: ReportService,
    private readonly comparisonService: ComparisonService,
    private readonly advancedPatternService: AdvancedPatternService,
    private readonly growthPercentileService: GrowthPercentileService,
  ) {}

  @Get('insights/:childId')
  async getInsights(
    @Req() req: any,
    @Param('childId') childId: string,
    @Query('days') days?: string,
  ) {
    const daysNum = days ? parseInt(days, 10) : 7;
    const patterns = await this.patternAnalysisService.analyzePatterns(
      childId,
      daysNum,
    );

    return {
      success: true,
      data: patterns,
    };
  }

  @Get('predictions/:childId')
  async getPredictions(@Req() req: any, @Param('childId') childId: string) {
    const predictions =
      await this.predictionService.generatePredictions(childId);

    return {
      success: true,
      data: predictions,
    };
  }

  @Get('reports/:childId/weekly')
  async getWeeklyReport(
    @Req() req: any,
    @Param('childId') childId: string,
    @Query('startDate') startDate?: string,
  ) {
    const start = startDate ? new Date(startDate) : null;
    const report = await this.reportService.generateWeeklyReport(
      childId,
      start,
    );

    return {
      success: true,
      data: report,
    };
  }

  @Get('reports/:childId/monthly')
  async getMonthlyReport(
    @Req() req: any,
    @Param('childId') childId: string,
    @Query('month') month?: string,
  ) {
    const monthDate = month ? new Date(month) : null;
    const report = await this.reportService.generateMonthlyReport(
      childId,
      monthDate,
    );

    return {
      success: true,
      data: report,
    };
  }

  @Get('export/:childId')
  async exportData(
    @Req() req: any,
    @Res() res: Response,
    @Param('childId') childId: string,
    @Query('format') format?: string,
    @Query('startDate') startDate?: string,
    @Query('endDate') endDate?: string,
  ) {
    const start = startDate ? new Date(startDate) : null;
    const end = endDate ? new Date(endDate) : null;
    const exportFormat = (format || 'json') as 'json' | 'csv' | 'pdf';

    const exportData = await this.reportService.exportData(
      childId,
      start,
      end,
      exportFormat,
    );

    // For PDF and CSV, send as downloadable file
    if (exportFormat === 'pdf' || exportFormat === 'csv') {
      const fileName = `activity-report-${childId}-${new Date().toISOString().split('T')[0]}.${exportFormat}`;

      res.setHeader('Content-Type', exportData.contentType);
      res.setHeader(
        'Content-Disposition',
        `attachment; filename="${fileName}"`,
      );

      if (exportFormat === 'pdf') {
        res.send(exportData.data);
      } else {
        res.send(exportData.data);
      }
    } else {
      // JSON format - return as regular response
      res.json({
        success: true,
        data: exportData,
      });
    }
  }

  @Get('compare')
  async compareChildren(
    @Req() req: any,
    @Query('childIds') childIdsParam: string,
    @Query('metric') metricParam: string,
    @Query('startDate') startDate: string,
    @Query('endDate') endDate: string,
  ) {
    // Validate required parameters
    if (!childIdsParam) {
      throw new BadRequestException('childIds query parameter is required (comma-separated)');
    }

    if (!metricParam) {
      throw new BadRequestException('metric query parameter is required');
    }

    if (!startDate || !endDate) {
      throw new BadRequestException('startDate and endDate query parameters are required');
    }

    // Parse child IDs
    const childIds = childIdsParam.split(',').filter(id => id.trim());

    if (childIds.length < 2) {
      throw new BadRequestException('At least 2 children are required for comparison');
    }

    // Validate metric
    const validMetrics = Object.values(ComparisonMetric);
    if (!validMetrics.includes(metricParam as ComparisonMetric)) {
      throw new BadRequestException(
        `Invalid metric. Must be one of: ${validMetrics.join(', ')}`,
      );
    }

    const metric = metricParam as ComparisonMetric;

    // Parse dates
    const start = new Date(startDate);
    const end = new Date(endDate);

    if (isNaN(start.getTime()) || isNaN(end.getTime())) {
      throw new BadRequestException('Invalid date format. Use ISO 8601 format (YYYY-MM-DD)');
    }

    if (start > end) {
      throw new BadRequestException('startDate must be before endDate');
    }

    // Perform comparison
    const comparison = await this.comparisonService.compareChildren(
      req.user.userId,
      childIds,
      metric,
      start,
      end,
    );

    return {
      success: true,
      data: comparison,
    };
  }

  /**
   * Advanced Analytics Endpoints
   */

  @Get('advanced/circadian-rhythm/:childId')
  async getCircadianRhythm(
    @CurrentUser() user: any,
    @Param('childId') childId: string,
    @Query('days') days?: string,
  ) {
    const daysNum = days ? parseInt(days, 10) : 14;

    try {
      const rhythm = await this.advancedPatternService.analyzeCircadianRhythm(
        childId,
        daysNum,
      );

      return {
        success: true,
        data: rhythm,
      };
    } catch (error) {
      throw new BadRequestException(error.message);
    }
  }

  @Get('advanced/anomalies/:childId')
  async detectAnomalies(
    @CurrentUser() user: any,
    @Param('childId') childId: string,
    @Query('days') days?: string,
  ) {
    const daysNum = days ? parseInt(days, 10) : 30;

    try {
      const anomalies = await this.advancedPatternService.detectAnomalies(
        childId,
        daysNum,
      );

      return {
        success: true,
        data: anomalies,
      };
    } catch (error) {
      throw new BadRequestException(error.message);
    }
  }

  @Get('advanced/clusters/:childId')
  async getActivityClusters(
    @CurrentUser() user: any,
    @Param('childId') childId: string,
    @Query('type') type: string,
    @Query('days') days?: string,
  ) {
    const daysNum = days ? parseInt(days, 10) : 30;

    // Validate activity type
    if (!Object.values(ActivityType).includes(type as ActivityType)) {
      throw new BadRequestException('Invalid activity type');
    }

    try {
      const clusters = await this.advancedPatternService.clusterActivities(
        childId,
        type as ActivityType,
        daysNum,
      );

      return {
        success: true,
        data: clusters,
      };
    } catch (error) {
      throw new BadRequestException(error.message);
    }
  }

  @Get('advanced/correlations/:childId')
  async getCorrelations(
    @CurrentUser() user: any,
    @Param('childId') childId: string,
    @Query('days') days?: string,
  ) {
    const daysNum = days ? parseInt(days, 10) : 14;

    try {
      const correlations = await this.advancedPatternService.analyzeCorrelations(
        childId,
        daysNum,
      );

      return {
        success: true,
        data: correlations,
      };
    } catch (error) {
      throw new BadRequestException(error.message);
    }
  }

  @Get('advanced/trends/:childId')
  async getTrends(
    @CurrentUser() user: any,
    @Param('childId') childId: string,
    @Query('type') type: string,
  ) {
    // Validate activity type
    if (!Object.values(ActivityType).includes(type as ActivityType)) {
      throw new BadRequestException('Invalid activity type');
    }

    try {
      const trends = await this.advancedPatternService.analyzeTrends(
        childId,
        type as ActivityType,
      );

      return {
        success: true,
        data: trends,
      };
    } catch (error) {
      throw new BadRequestException(error.message);
    }
  }

  /**
   * Growth Analytics Endpoints
   */

  @Post('growth/percentile/:childId')
  async calculateGrowthPercentile(
    @CurrentUser() user: any,
    @Param('childId') childId: string,
    @Body() measurement: {
      date: string;
      weight?: number;
      height?: number;
      headCircumference?: number;
    },
  ) {
    try {
      const measurementData = {
        date: new Date(measurement.date),
        weight: measurement.weight,
        height: measurement.height,
        headCircumference: measurement.headCircumference,
      };

      const percentiles = await this.growthPercentileService.calculateGrowthPercentiles(
        childId,
        measurementData,
      );

      return {
        success: true,
        data: percentiles,
      };
    } catch (error) {
      throw new BadRequestException(error.message);
    }
  }

  @Get('growth/analysis/:childId')
  async analyzeGrowth(
    @CurrentUser() user: any,
    @Param('childId') childId: string,
  ) {
    try {
      const analysis = await this.growthPercentileService.analyzeGrowth(childId);

      return {
        success: true,
        data: analysis,
      };
    } catch (error) {
      throw new BadRequestException(error.message);
    }
  }

  /**
   * Comprehensive Analytics Dashboard Endpoint
   */

  @Get('dashboard/:childId')
  async getAnalyticsDashboard(
    @CurrentUser() user: any,
    @Param('childId') childId: string,
    @Query('days') days?: string,
  ) {
    const daysNum = days ? parseInt(days, 10) : 7;

    try {
      // Fetch all analytics in parallel
      const [
        patterns,
        predictions,
        recentActivities,
        growthAnalysis,
        anomalies,
      ] = await Promise.all([
        this.patternAnalysisService.analyzePatterns(childId, daysNum),
        this.predictionService.generatePredictions(childId),
        this.reportService.generateWeeklyReport(childId).catch(() => null),
        this.growthPercentileService.analyzeGrowth(childId).catch(() => null),
        this.advancedPatternService.detectAnomalies(childId, daysNum).catch(() => null),
      ]);

      return {
        success: true,
        data: {
          patterns,
          predictions,
          recentSummary: recentActivities,
          growth: growthAnalysis,
          alerts: anomalies?.alerts || [],
          generatedAt: new Date(),
        },
      };
    } catch (error) {
      throw new BadRequestException(error.message);
    }
  }
}
