<?php

namespace api\v2\objects\history;
use api\v2\Base;
use Exception;

use function api\v2\import_common;
import_common();

/**
 * Alert History API endpoint for historical state change data.
 * 
 * This endpoint provides aggregated alert history data from the nagios_statehistory table,
 * compatible with the existing Alert History dashlet functionality.
 * 
 * Usage:
 * GET /api/v2/objects/history/alerts?lookback=365
 * GET /api/v2/objects/history/alerts?start_date=2024-01-01&end_date=2024-12-31
 */
class alerts extends Base {

    /**
     * Authorization for GET requests
     * Users need to be authenticated to access historical data
     */
    public function authorized_for_get() {
        return true; // Basic auth handled by parent API system
    }

    /**
     * Get alert history data aggregated by day
     * 
     * @return array Alert history data with metadata
     */
    public function get() {
        try {
            // Parse request parameters
            $lookback = intval(grab_request_var("lookback", "365"));
            $start_date = grab_request_var("start_date", "");
            $end_date = grab_request_var("end_date", "");
            $format = grab_request_var("format", "daily");

            // Validate parameters
            if ($lookback <= 0) {
                throw new Exception("lookback must be a positive integer", 400);
            }

            if ($lookback > 3650) { // 10 years max
                throw new Exception("lookback cannot exceed 3650 days", 400);
            }

            // Build the SQL query based on the existing alert history logic
            $sql = $this->buildAlertHistoryQuery($lookback, $start_date, $end_date);
            
            // Execute query
            $result = exec_sql_query(DB_NDOUTILS, $sql);
            
            if ($result === null) {
                throw new Exception("Database query failed", 500);
            }

            $data = $result->GetArray();
            
            // Fill gaps in data to ensure continuous date coverage
            $corrected_data = $this->fillDateGaps($data, $lookback, $start_date, $end_date);
            
            // Calculate metadata
            $metadata = $this->calculateMetadata($corrected_data, $lookback, $start_date, $end_date);

            return [
                'data' => $corrected_data,
                'metadata' => $metadata
            ];

        } catch (Exception $e) {
            throw new Exception($e->getMessage(), $e->getCode() ?: 500);
        }
    }

    /**
     * Build SQL query for alert history data
     * 
     * @param int $lookback Number of days to look back
     * @param string $start_date Start date (optional)
     * @param string $end_date End date (optional)
     * @return string SQL query
     */
    private function buildAlertHistoryQuery($lookback, $start_date = "", $end_date = "") {
        
        // Base query structure from existing alert history logic
        $sql = "SELECT 
                    DATE(state_time) as date, 
                    COUNT(*) as count 
                FROM nagios.nagios_statehistory 
                WHERE state_type != 0";

        // Add date range conditions
        if (!empty($start_date) && !empty($end_date)) {
            // Use explicit date range
            $sql .= " AND DATE(state_time) >= '" . escape_sql_param($start_date, DB_NDOUTILS) . "'";
            $sql .= " AND DATE(state_time) <= '" . escape_sql_param($end_date, DB_NDOUTILS) . "'";
        } else {
            // Use lookback period (default behavior)
            $sql .= " AND state_time > DATE_SUB(NOW(), INTERVAL $lookback DAY)";
        }

        $sql .= " GROUP BY DATE(state_time)
                  ORDER BY DATE(state_time)";

        return $sql;
    }

    /**
     * Fill gaps in date data to ensure continuous coverage
     * Based on the existing alert history gap-filling logic
     * 
     * @param array $data Raw query results
     * @param int $lookback Lookback period in days
     * @param string $start_date Start date (optional)
     * @param string $end_date End date (optional)
     * @return array Data with filled gaps
     */
    private function fillDateGaps($data, $lookback, $start_date = "", $end_date = "") {
        
        // Determine start date for gap filling
        if (!empty($data) && isset($data[0]['day'])) {
            $candidate_date = date_create($data[0]['day']);
        } else {
            // Fallback based on parameters
            if (!empty($start_date)) {
                $candidate_date = date_create($start_date);
            } else {
                $candidate_date = $this->truncatedDateTime("now -$lookback days");
            }
        }

        $corrected_data = array();
        $one_day = new \DateInterval("P1D");

        // Fill gaps between existing data points
        foreach ($data as $record) {
            if (isset($record['day'])) {
                $record_date = date_create($record['day']);
            } else {
                $record_date = false;
            }

            // Fill any missing days before this record
            if ($record_date) {
                while ($record_date > $candidate_date) {
                    $corrected_data[] = array(
                        'date' => $candidate_date, 
                        'value' => 0
                    );
                    $candidate_date->add($one_day);
                }
            }
            // Add the actual record
            $corrected_data[] = $record;
            $candidate_date->add($one_day);
        }

        // Fill remaining days up to end date
        $end_target = !empty($end_date) ? 
            date_create($end_date) : 
            $this->truncatedDateTime('now');
            
        while ($end_target >= $candidate_date) {
            $corrected_data[] = array(
                'date' => $candidate_date, 
                'value' => 0
            );
            $candidate_date->add($one_day);
        }

        return $corrected_data;
    }

    /**
     * Calculate metadata for the response
     * 
     * @param array $data Processed alert data
     * @param int $lookback Lookback period
     * @param string $start_date Start date
     * @param string $end_date End date  
     * @return array Metadata
     */
    private function calculateMetadata($data, $lookback, $start_date, $end_date) {
        $total_alerts = array_sum(array_column($data, 'value'));
        
        $metadata = [
            'total_alerts' => $total_alerts,
            'data_points' => count($data),
            'lookback_days' => $lookback
        ];

        if (!empty($data) && isset($data[0]['day']) && isset(end($data)['day'])) {
            $metadata['start_date'] = $data[0]['day'];
            $metadata['end_date'] = end($data)['day'];
        }

        if (!empty($start_date)) {
            $metadata['requested_start_date'] = $start_date;
        }
        
        if (!empty($end_date)) {
            $metadata['requested_end_date'] = $end_date;
        }

        return $metadata;
    }

    /**
     * Helper function to create DateTime with only day resolution
     * Based on alert_history_truncated_datetime from existing code
     * 
     * @param string $datestring Date string to parse
     * @return \DateTime Truncated DateTime object
     */
    private function truncatedDateTime($datestring) {
        $as_datetime = date_create($datestring);
        $truncated_to_date = $as_datetime->format('Y-m-d');
        $as_truncated = date_create($truncated_to_date);
        return $as_truncated;
    }
}