/**
 * KPI Controller
 * 
 * API endpoints để quản lý dữ liệu KPI
 */

import { Request, Response } from 'express';
import { KPI } from '../models/KPI';
import { Project } from '../models/Project';
import { collectKPIForProject, getKPIsFromV2API } from '../services/kpiCollectorService';
import type { IKPIData } from '../services/kpiCollectorService';
import mongoose from 'mongoose';

/**
 * Get KPI data for a project (from MongoDB - legacy)
 * GET /api/kpis?projectId=xxx&startDate=xxx&endDate=xxx
 */
export const getKPIs = async (req: Request, res: Response) => {
  try {
    const { projectId, startDate, endDate } = req.query;

    if (!projectId) {
      return res.status(400).json({
        success: false,
        message: 'projectId is required',
      });
    }

    const query: any = {
      siteId: new mongoose.Types.ObjectId(projectId as string),
    };

    if (startDate || endDate) {
      query.date = {};
      if (startDate) {
        query.date.$gte = new Date(startDate as string);
      }
      if (endDate) {
        query.date.$lte = new Date(endDate as string);
      }
    }

    const kpis = await KPI.find(query).sort({ date: -1 });

    res.json({
      success: true,
      data: kpis,
    });
  } catch (error: any) {
    console.error('[KPI Controller] Error getting KPIs:', error);
    res.status(500).json({
      success: false,
      message: 'Error getting KPIs',
      error: error.message,
    });
  }
};

/**
 * Get KPI data directly from V2 API (live, no MongoDB)
 * GET /api/kpis/live?projectId=xxx&startDate=xxx&endDate=xxx
 */
export const getKPIsLive = async (req: Request, res: Response) => {
  try {
    const { projectId, startDate, endDate } = req.query;

    if (!projectId) {
      return res.status(400).json({
        success: false,
        message: 'projectId is required',
      });
    }

    // Verify project exists
    const project = await Project.findById(projectId);
    if (!project) {
      return res.status(404).json({
        success: false,
        message: 'Project not found',
      });
    }

    // Get today's date (start of day in local timezone)
    const now = new Date();
    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const todayEnd = new Date(today);
    todayEnd.setHours(23, 59, 59, 999);
    
    // Default date range: last 30 days from today
    let end: Date;
    let start: Date;
    
    if (endDate) {
      end = new Date(endDate as string);
      end.setHours(23, 59, 59, 999);
    } else {
      // Default: today
      end = new Date(todayEnd);
    }
    
    if (startDate) {
      start = new Date(startDate as string);
      start.setHours(0, 0, 0, 0);
    } else {
      // Default: 30 days ago from today
      start = new Date(today);
      start.setDate(start.getDate() - 30);
      start.setHours(0, 0, 0, 0);
    }

    // Ensure dates are valid
    if (isNaN(start.getTime()) || isNaN(end.getTime())) {
      return res.status(400).json({
        success: false,
        message: 'Invalid date format',
      });
    }
    
    // CRITICAL: Ensure end date is NOT in the future - clamp to today
    if (end > todayEnd) {
      end = new Date(todayEnd);
    }
    
    // CRITICAL: Ensure start date is NOT in the future
    if (start > todayEnd) {
      start = new Date(today);
      start.setDate(start.getDate() - 30);
      start.setHours(0, 0, 0, 0);
    }
    
    // Ensure start is not after end
    if (start > end) {
      end = new Date(todayEnd);
      start = new Date(today);
      start.setDate(start.getDate() - 30);
      start.setHours(0, 0, 0, 0);
    }
    
    // Final validation: ensure end date is exactly today or before
    if (end > todayEnd) {
      end = new Date(todayEnd);
    }
    
    // Final validation: ensure start date is not in future
    if (start > todayEnd) {
      start = new Date(today);
      start.setDate(start.getDate() - 30);
      start.setHours(0, 0, 0, 0);
    }
    

    // Limit date range to prevent too many API calls (max 90 days)
    const daysDiff = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
    if (daysDiff > 90) {
      return res.status(400).json({
        success: false,
        message: 'Date range cannot exceed 90 days',
      });
    }


    try {
      // Add timeout wrapper (max 60 seconds)
      const timeoutPromise = new Promise((_, reject) => {
        setTimeout(() => reject(new Error('Request timeout after 60 seconds')), 60000);
      });

      const kpiDataPromise = getKPIsFromV2API(projectId as string, start, end);
      
      const kpiData = await Promise.race([kpiDataPromise, timeoutPromise]) as IKPIData[];

      // Transform to match KPI model format for frontend compatibility
      const formattedData = kpiData.map(kpi => {
        // Ensure all values are numbers (handle null/undefined)
        const production = typeof kpi.production === 'number' ? kpi.production : 0;
        const pr = typeof kpi.pr === 'number' ? kpi.pr : 0;
        const availability = typeof kpi.availability === 'number' ? kpi.availability : 0;
        const specificYield = typeof kpi.specificYield === 'number' ? kpi.specificYield : 0;
        const irradiation = typeof kpi.irradiation === 'number' ? kpi.irradiation : 0;
        
        return {
          _id: `live-${kpi.date.getTime()}`,
          siteId: projectId,
          date: kpi.date,
          production,
          pr,
          availability,
          specificYield,
          irradiation,
          createdAt: kpi.date,
          updatedAt: kpi.date,
        };
      });

      res.json({
        success: true,
        data: formattedData,
        source: 'live',
        message: `Fetched ${formattedData.length} days of KPI data from Meteocontrol V2 API`,
      });
    } catch (apiError: any) {
      // console.error(`[KPI Live] Error fetching from V2 API:`, apiError.message, apiError.stack);
      // Return empty array instead of error to allow frontend to handle gracefully
      res.json({
        success: true,
        data: [],
        source: 'live',
        message: `No KPI data available: ${apiError.message}`,
        error: apiError.message,
      });
    }
  } catch (error: any) {
    console.error('[KPI Controller] Error getting live KPIs:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Error getting live KPI data',
      error: error.message,
    });
  }
};

/**
 * Get latest KPI data for a project
 * GET /api/kpis/latest?projectId=xxx
 */
export const getLatestKPI = async (req: Request, res: Response) => {
  try {
    const { projectId } = req.query;

    if (!projectId) {
      return res.status(400).json({
        success: false,
        message: 'projectId is required',
      });
    }

    const kpi = await KPI.findOne({
      siteId: new mongoose.Types.ObjectId(projectId as string),
    }).sort({ date: -1 });

    if (!kpi) {
      return res.status(404).json({
        success: false,
        message: 'KPI data not found',
      });
    }

    res.json({
      success: true,
      data: kpi,
    });
  } catch (error: any) {
    console.error('[KPI Controller] Error getting latest KPI:', error);
    res.status(500).json({
      success: false,
      message: 'Error getting latest KPI',
      error: error.message,
    });
  }
};

/**
 * Manually trigger KPI collection for a project
 * POST /api/kpis/collect?projectId=xxx&date=xxx (optional)
 */
export const collectKPI = async (req: Request, res: Response) => {
  try {
    const { projectId, date, days } = req.query;

    if (!projectId) {
      return res.status(400).json({
        success: false,
        message: 'projectId is required',
      });
    }

    // Verify project exists
    const project = await Project.findById(projectId);
    if (!project) {
      return res.status(404).json({
        success: false,
        message: 'Project not found',
      });
    }

    // If days is specified, collect KPI for multiple days
    if (days && parseInt(days as string) > 1) {
      const numDays = parseInt(days as string);
      const startDate = date ? new Date(date as string) : new Date();
      startDate.setDate(startDate.getDate() - numDays + 1); // Start from numDays ago

      let successCount = 0;
      let failCount = 0;

      for (let i = 0; i < numDays; i++) {
        const targetDate = new Date(startDate);
        targetDate.setDate(startDate.getDate() + i);
        targetDate.setHours(0, 0, 0, 0);

        const success = await collectKPIForProject(projectId as string, targetDate);
        if (success) {
          successCount++;
        } else {
          failCount++;
        }

        // Small delay to respect rate limits
        if (i < numDays - 1) {
          await new Promise(resolve => setTimeout(resolve, 1000));
        }
      }

      res.json({
        success: true,
        message: `KPI collection completed: ${successCount} success, ${failCount} failed`,
        data: {
          successCount,
          failCount,
          totalDays: numDays,
        },
      });
    } else {
      // Single date collection
      const targetDate = date ? new Date(date as string) : new Date();
      const success = await collectKPIForProject(projectId as string, targetDate);

      if (success) {
        res.json({
          success: true,
          message: 'KPI collection completed successfully',
        });
      } else {
        res.status(500).json({
          success: false,
          message: 'KPI collection failed',
        });
      }
    }
  } catch (error: any) {
    console.error('[KPI Controller] Error collecting KPI:', error);
    res.status(500).json({
      success: false,
      message: 'Error collecting KPI',
      error: error.message,
    });
  }
};

/**
 * Get KPI statistics for a project
 * GET /api/kpis/stats?projectId=xxx&startDate=xxx&endDate=xxx
 */
export const getKPIStats = async (req: Request, res: Response) => {
  try {
    const { projectId, startDate, endDate } = req.query;

    if (!projectId) {
      return res.status(400).json({
        success: false,
        message: 'projectId is required',
      });
    }

    const query: any = {
      siteId: new mongoose.Types.ObjectId(projectId as string),
    };

    if (startDate || endDate) {
      query.date = {};
      if (startDate) {
        query.date.$gte = new Date(startDate as string);
      }
      if (endDate) {
        query.date.$lte = new Date(endDate as string);
      }
    }

    const kpis = await KPI.find(query);

    if (kpis.length === 0) {
      return res.json({
        success: true,
        data: {
          count: 0,
          avgProduction: 0,
          avgPR: 0,
          avgAvailability: 0,
          avgSpecificYield: 0,
          totalProduction: 0,
        },
      });
    }

    const stats = {
      count: kpis.length,
      avgProduction: kpis.reduce((sum, kpi) => sum + (kpi.production || 0), 0) / kpis.length,
      avgPR: kpis.reduce((sum, kpi) => sum + (kpi.pr || 0), 0) / kpis.length,
      avgAvailability: kpis.reduce((sum, kpi) => sum + (kpi.availability || 0), 0) / kpis.length,
      avgSpecificYield: kpis.reduce((sum, kpi) => sum + (kpi.specificYield || 0), 0) / kpis.length,
      totalProduction: kpis.reduce((sum, kpi) => sum + (kpi.production || 0), 0),
    };

    res.json({
      success: true,
      data: stats,
    });
  } catch (error: any) {
    console.error('[KPI Controller] Error getting KPI stats:', error);
    res.status(500).json({
      success: false,
      message: 'Error getting KPI stats',
      error: error.message,
    });
  }
};
