<?php

namespace SSCI\Classes;

class Patrol
{
    private $db;
    private $config;

    public function __construct($db, $config = null)
    {
        $this->db = $db;
        $this->config = $config;
    }

    /**
     * Get or create current hourly patrol for a post
     */
    public function getOrCreateCurrentPatrol($postId)
    {
        $now = new \DateTime();
        $patrolHour = $now->format('Y-m-d H'); // Format: 2025-12-15 14
        $patrolStartTime = $now->format('Y-m-d H:00:00');
        $patrolEndTime = $now->format('Y-m-d H:59:59');

        // Try to get existing patrol
        $patrol = $this->db->fetch(
            "SELECT * FROM patrols WHERE post_id = ? AND patrol_hour = ?",
            [$postId, $patrolHour]
        );

        if ($patrol) {
            return $patrol;
        }

        // Create new patrol record
        $this->db->query(
            "INSERT INTO patrols (post_id, patrol_hour, patrol_date, patrol_start_time, patrol_end_time, status, total_points, guards_assigned)
             VALUES (?, ?, ?, ?, ?, 'Missed', 4, ?)",
            [
                $postId,
                $patrolHour,
                $now->format('Y-m-d'),
                $patrolStartTime,
                $patrolEndTime,
                $this->getAssignedGuardsCount($postId)
            ]
        );

        $patrolId = $this->db->lastInsertId();

        // Create point status records for this patrol
        $points = $this->db->fetchAll(
            "SELECT id FROM patrol_points WHERE post_id = ? AND is_active = TRUE",
            [$postId]
        );

        foreach ($points as $point) {
            $this->db->query(
                "INSERT INTO patrol_point_status (patrol_id, patrol_point_id, max_scans, status)
                 VALUES (?, ?, 2, 'Missed')",
                [$patrolId, $point['id']]
            );
        }

        return $this->db->fetch("SELECT * FROM patrols WHERE id = ?", [$patrolId]);
    }

    /**
     * Record a QR code scan
     */
    public function recordScan($postId, $qrCode, $guardId, $latitude = null, $longitude = null, $deviceInfo = null)
    {
        // Get patrol point by QR code
        $point = $this->db->fetch(
            "SELECT * FROM patrol_points WHERE post_id = ? AND qr_code = ? AND is_active = TRUE",
            [$postId, $qrCode]
        );

        if (!$point) {
            return ['success' => false, 'error' => 'Invalid QR code or point not found'];
        }

        // Get guard's current assignment
        $assignment = $this->db->fetch(
            "SELECT * FROM guard_post_assignments WHERE post_id = ? AND guard_id = ? AND status = 'Active'",
            [$postId, $guardId]
        );

        if (!$assignment) {
            return ['success' => false, 'error' => 'Guard not assigned to this post'];
        }

        // Get or create current patrol
        $patrol = $this->getOrCreateCurrentPatrol($postId);

        // Check if this point has already reached max scans (2) in this hour
        $pointStatus = $this->db->fetch(
            "SELECT * FROM patrol_point_status WHERE patrol_id = ? AND patrol_point_id = ?",
            [$patrol['id'], $point['id']]
        );

        if ($pointStatus && $pointStatus['scan_count'] >= 2) {
            // Point has already reached max scans
            return [
                'success' => false,
                'error' => 'This point has already reached the maximum scans (2) for this hour',
                'point' => $point,
                'current_scans' => $pointStatus['scan_count']
            ];
        }

        // Record the scan
        $now = new \DateTime();
        $scanHour = $now->format('Y-m-d H');

        $this->db->query(
            "INSERT INTO patrol_scans (post_id, patrol_point_id, guard_id, assignment_id, scan_timestamp, scan_hour, latitude, longitude, device_info)
             VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
            [
                $postId,
                $point['id'],
                $guardId,
                $assignment['id'],
                $now->format('Y-m-d H:i:s'),
                $scanHour,
                $latitude,
                $longitude,
                $deviceInfo
            ]
        );

        // Refresh point status since it may have been just created
        $pointStatus = $this->db->fetch(
            "SELECT * FROM patrol_point_status WHERE patrol_id = ? AND patrol_point_id = ?",
            [$patrol['id'], $point['id']]
        );

        if ($pointStatus) {
            $newScanCount = $pointStatus['scan_count'] + 1;
            $newScore = min($newScanCount, 2); // Max 2 points per point
            $newStatus = $newScanCount >= 2 ? 'Completed' : 'Incomplete';

            // Build update query based on whether first_scan_time is set
            if ($pointStatus['first_scan_time']) {
                // First scan time already set, don't update it
                $this->db->query(
                    "UPDATE patrol_point_status 
                     SET scan_count = ?, score = ?, status = ?, last_scan_time = ?, updated_at = NOW()
                     WHERE id = ?",
                    [
                        $newScanCount,
                        $newScore,
                        $newStatus,
                        $now->format('Y-m-d H:i:s'),
                        $pointStatus['id']
                    ]
                );
            } else {
                // Set first_scan_time on first scan
                $this->db->query(
                    "UPDATE patrol_point_status 
                     SET scan_count = ?, score = ?, status = ?, first_scan_time = ?, last_scan_time = ?, updated_at = NOW()
                     WHERE id = ?",
                    [
                        $newScanCount,
                        $newScore,
                        $newStatus,
                        $now->format('Y-m-d H:i:s'),
                        $now->format('Y-m-d H:i:s'),
                        $pointStatus['id']
                    ]
                );
            }

            // Update patrol totals
            $this->updatePatrolScore($patrol['id']);
        }

        return [
            'success' => true,
            'message' => 'Scan recorded successfully',
            'point' => $point,
            'patrol' => $this->getPatrolDetails($patrol['id'])
        ];
    }

    /**
     * Update patrol score and status
     */
    private function updatePatrolScore($patrolId)
    {
        // Get all point statuses for this patrol
        $pointStatuses = $this->db->fetchAll(
            "SELECT * FROM patrol_point_status WHERE patrol_id = ?",
            [$patrolId]
        );

        $totalScans = 0;
        $totalScore = 0;
        $completedPoints = 0;
        $incompletePoints = 0;

        foreach ($pointStatuses as $ps) {
            $totalScans += $ps['scan_count'];
            $totalScore += $ps['score'];
            if ($ps['status'] === 'Completed') {
                $completedPoints++;
            } elseif ($ps['scan_count'] > 0) {
                $incompletePoints++;
            }
        }

        // Determine patrol status
        $status = 'Missed';
        if ($totalScore > 0 && $totalScore < 8) {
            $status = 'Incomplete';
        } elseif ($totalScore >= 8) {
            $status = 'Completed';
        }

        $completionPercentage = round(($totalScore / 8) * 100);

        $this->db->query(
            "UPDATE patrols SET total_scans = ?, score = ?, status = ?, completion_percentage = ?, updated_at = NOW()
             WHERE id = ?",
            [$totalScans, $totalScore, $status, $completionPercentage, $patrolId]
        );
    }

    /**
     * Get patrol details with point statuses
     */
    public function getPatrolDetails($patrolId)
    {
        $patrol = $this->db->fetch("SELECT * FROM patrols WHERE id = ?", [$patrolId]);

        if (!$patrol) {
            return null;
        }

        $pointStatuses = $this->db->fetchAll(
            "SELECT pps.*, pp.point_name, pp.qr_code, pp.location_description
             FROM patrol_point_status pps
             JOIN patrol_points pp ON pps.patrol_point_id = pp.id
             WHERE pps.patrol_id = ?
             ORDER BY pp.point_name",
            [$patrolId]
        );

        return [
            'id' => $patrol['id'],
            'post_id' => $patrol['post_id'],
            'patrol_hour' => $patrol['patrol_hour'],
            'status' => $patrol['status'],
            'score' => $patrol['score'],
            'total_scans' => $patrol['total_scans'],
            'completion_percentage' => $patrol['completion_percentage'],
            'total_points' => $patrol['total_points'],
            'points' => $pointStatuses,
            'reminder_sent' => $patrol['reminder_sent'],
            'patrol_start_time' => $patrol['patrol_start_time'],
            'patrol_end_time' => $patrol['patrol_end_time']
        ];
    }

    /**
     * Get current hour status for a post
     */
    public function getCurrentHourStatus($postId)
    {
        $now = new \DateTime();
        $patrolHour = $now->format('Y-m-d H');

        $patrol = $this->db->fetch(
            "SELECT * FROM patrols WHERE post_id = ? AND patrol_hour = ?",
            [$postId, $patrolHour]
        );

        if (!$patrol) {
            $patrol = $this->getOrCreateCurrentPatrol($postId);
        }

        return $this->getPatrolDetails($patrol['id']);
    }

    /**
     * Get patrol history for a post
     */
    public function getPatrolHistory($postId, $days = 7, $limit = 50)
    {
        $since = date('Y-m-d', strtotime("-{$days} days"));

        $patrols = $this->db->fetchAll(
            "SELECT * FROM patrols 
             WHERE post_id = ? AND patrol_date >= ?
             ORDER BY patrol_date DESC, patrol_hour DESC
             LIMIT ?",
            [$postId, $since, $limit]
        );

        return array_map(function ($patrol) {
            return $this->getPatrolDetails($patrol['id']);
        }, $patrols);
    }

    /**
     * Get today's patrol summary for a post
     */
    public function getTodaysSummary($postId)
    {
        $today = date('Y-m-d');

        $patrols = $this->db->fetchAll(
            "SELECT * FROM patrols 
             WHERE post_id = ? AND patrol_date = ?
             ORDER BY patrol_hour ASC",
            [$postId, $today]
        );

        $stats = [
            'total_patrols' => count($patrols),
            'completed' => 0,
            'incomplete' => 0,
            'missed' => 0,
            'total_score' => 0,
            'average_completion' => 0,
            'patrols' => []
        ];

        foreach ($patrols as $patrol) {
            $stats['patrols'][] = $this->getPatrolDetails($patrol['id']);
            $stats['total_score'] += $patrol['score'];

            switch ($patrol['status']) {
                case 'Completed':
                    $stats['completed']++;
                    break;
                case 'Incomplete':
                    $stats['incomplete']++;
                    break;
                case 'Missed':
                    $stats['missed']++;
                    break;
            }
        }

        if ($stats['total_patrols'] > 0) {
            $stats['average_completion'] = round(
                array_reduce($patrols, function ($carry, $p) {
                    return $carry + $p['completion_percentage'];
                }, 0) / $stats['total_patrols']
            );
        }

        return $stats;
    }

    /**
     * Check if patrol needs reminder (10 minutes before end of hour)
     */
    public function shouldSendReminder($patrolId)
    {
        $patrol = $this->db->fetch("SELECT * FROM patrols WHERE id = ?", [$patrolId]);

        if (!$patrol || $patrol['reminder_sent'] || $patrol['status'] === 'Completed') {
            return false;
        }

        // Check if 50 minutes into the hour (10 minutes to deadline)
        $now = new \DateTime();
        $minute = (int)$now->format('i');

        return $minute >= 50;
    }

    /**
     * Send reminder notification
     */
    public function sendReminder($patrolId, $notification)
    {
        $patrol = $this->db->fetch(
            "SELECT p.*, po.post_name, po.location FROM patrols p
             JOIN posts po ON p.post_id = po.id
             WHERE p.id = ?",
            [$patrolId]
        );

        if (!$patrol) {
            return false;
        }

        // Get assigned guards
        $guards = $this->db->fetchAll(
            "SELECT DISTINCT s.user_id, u.name 
             FROM guard_post_assignments gpa
             JOIN staff s ON gpa.guard_id = s.id
             JOIN users u ON s.user_id = u.id
             WHERE gpa.post_id = ? AND gpa.status = 'Active'",
            [$patrol['post_id']]
        );

        if (empty($guards)) {
            return false;
        }

        foreach ($guards as $guard) {
            if ($notification) {
                $remainingPoints = 4 - count(array_filter(
                    $this->db->fetchAll(
                        "SELECT * FROM patrol_point_status WHERE patrol_id = ? AND status = 'Completed'",
                        [$patrolId]
                    )
                ));

                $notification
                    ->reset()
                    ->forUser($guard['user_id'])
                    ->setTitle('Patrol Reminder ⏰')
                    ->setMessage("Patrol at " . $patrol['post_name'] . " - 10 minutes remaining. " . $remainingPoints . " points incomplete. Score: " . $patrol['score'] . "/8")
                    ->setType('warning')
                    ->addCallToAction('Continue Patrol', "/dashboard?page=patrols&post_id=" . $patrol['post_id'])
                    ->via(['sms', 'push', 'in-app'])
                    ->send();
            }
        }

        // Mark reminder as sent
        $this->db->query("UPDATE patrols SET reminder_sent = TRUE WHERE id = ?", [$patrolId]);

        return true;
    }

    /**
     * Get countdown to next patrol hour
     */
    public function getCountdownToNextHour()
    {
        $now = new \DateTime();
        $nextHour = clone $now;
        
        // Set to next hour at minute 00
        $nextHour->modify('+1 hour');
        $nextHour->setTime($nextHour->format('H'), 0, 0);

        $diff = $nextHour->diff($now);
        $minutes = $diff->i;
        $seconds = $diff->s;

        return [
            'total_seconds' => ($minutes * 60) + $seconds,
            'minutes' => $minutes,
            'seconds' => $seconds,
            'next_hour' => $nextHour->format('Y-m-d H:00:00')
        ];
    }

    /**
     * Helper: Get staff ID by user ID
     */
    private function getStaffIdByUserId($userId)
    {
        $staff = $this->db->fetch("SELECT id FROM staff WHERE user_id = ?", [$userId]);
        return $staff ? $staff['id'] : null;
    }

    /**
     * Helper: Get assigned guards count for a post
     */
    private function getAssignedGuardsCount($postId)
    {
        $result = $this->db->fetch(
            "SELECT COUNT(DISTINCT guard_id) as count FROM guard_post_assignments 
             WHERE post_id = ? AND status = 'Active'",
            [$postId]
        );
        return $result['count'] ?? 0;
    }

    /**
     * Get scan recency info
     */
    public function getLastScanInfo($postId)
    {
        $lastScan = $this->db->fetch(
            "SELECT ps.*, pp.point_name, u.name as guard_name
             FROM patrol_scans ps
             JOIN patrol_points pp ON ps.patrol_point_id = pp.id
             JOIN users u ON ps.guard_id = u.id
             WHERE ps.post_id = ?
             ORDER BY ps.scan_timestamp DESC
             LIMIT 1",
            [$postId]
        );

        return $lastScan;
    }

    /**
     * Get QR code details by code
     */
    public function getQRCodeDetails($qrCode)
    {
        $point = $this->db->fetch(
            "SELECT * FROM patrol_points WHERE qr_code = ? AND is_active = TRUE",
            [$qrCode]
        );

        return $point;
    }
}
