<?php

namespace WHPBackup;

require_once('/docker/whp/web/libs/mysqlmgmt.php');

use PDO;
use Exception;
use DateTime;

class BackupSchedule {
    private $db;
    private $id;
    private $data = [];
    
    public function __construct(PDO $db = null, $id = null) {
        if ($db === null) {
            $mysql = new \mysqlmgmt();
            $this->db = $mysql->getMySQLConnection();
            $this->db->exec("USE whp");
        } else {
            $this->db = $db;
        }
        
        if ($id) {
            $this->load($id);
        }
    }
    
    public function load($id) {
        $stmt = $this->db->prepare("SELECT * FROM backup_schedules WHERE id = ?");
        $stmt->execute([$id]);
        $this->data = $stmt->fetch(PDO::FETCH_ASSOC);
        if ($this->data) {
            $this->id = $id;
            return true;
        }
        return false;
    }
    
    public function create($data) {
        $required = ['user', 'target_id', 'backup_type', 'schedule_type', 'schedule_time'];
        foreach ($required as $field) {
            if (!isset($data[$field]) || empty($data[$field])) {
                throw new Exception("Missing required field: $field");
            }
        }
        
        // Calculate next run time
        $nextRun = $this->calculateNextRun($data['schedule_type'], $data['schedule_time'], $data['schedule_day'] ?? null);
        
        $fields = ['user', 'target_id', 'backup_type', 'resource_name', 'schedule_type', 
                   'schedule_time', 'schedule_day', 'max_retention', 'is_active', 'next_run_at'];
        $placeholders = array_fill(0, count($fields), '?');
        
        $sql = "INSERT INTO backup_schedules (" . implode(', ', $fields) . ") VALUES (" . implode(', ', $placeholders) . ")";
        $stmt = $this->db->prepare($sql);
        
        $values = [
            $data['user'],
            $data['target_id'],
            $data['backup_type'],
            empty($data['resource_name']) ? null : $data['resource_name'],
            $data['schedule_type'],
            $data['schedule_time'],
            empty($data['schedule_day']) ? null : intval($data['schedule_day']),
            $data['max_retention'] ?? 30,
            isset($data['is_active']) ? (int)$data['is_active'] : 1,
            $nextRun
        ];
        
        if ($stmt->execute($values)) {
            $this->id = $this->db->lastInsertId();
            $this->load($this->id);
            return true;
        }
        
        return false;
    }
    
    public function update($data) {
        if (!$this->id) {
            throw new Exception("Cannot update non-existent schedule");
        }
        
        $fields = ['user', 'target_id', 'backup_type', 'resource_name', 'schedule_type', 
                   'schedule_time', 'schedule_day', 'max_retention', 'is_active'];
        $setParts = [];
        $values = [];
        
        foreach ($fields as $field) {
            if (isset($data[$field])) {
                $setParts[] = "$field = ?";
                if ($field === 'resource_name') {
                    $values[] = empty($data[$field]) ? null : $data[$field];
                } elseif ($field === 'schedule_day') {
                    $values[] = empty($data[$field]) ? null : intval($data[$field]);
                } elseif ($field === 'is_active') {
                    $values[] = (int)$data[$field];
                } else {
                    $values[] = $data[$field];
                }
            }
        }
        
        // Recalculate next run time if schedule parameters changed
        if (isset($data['schedule_type']) || isset($data['schedule_time']) || isset($data['schedule_day'])) {
            $scheduleType = $data['schedule_type'] ?? $this->data['schedule_type'];
            $scheduleTime = $data['schedule_time'] ?? $this->data['schedule_time'];
            $scheduleDay = isset($data['schedule_day']) ? 
                (empty($data['schedule_day']) ? null : intval($data['schedule_day'])) : 
                $this->data['schedule_day'];
            
            $nextRun = $this->calculateNextRun($scheduleType, $scheduleTime, $scheduleDay);
            $setParts[] = "next_run_at = ?";
            $values[] = $nextRun;
        }
        
        if (empty($setParts)) {
            return true; // No changes
        }
        
        $sql = "UPDATE backup_schedules SET " . implode(', ', $setParts) . " WHERE id = ?";
        $values[] = $this->id;
        
        $stmt = $this->db->prepare($sql);
        if ($stmt->execute($values)) {
            $this->load($this->id);
            return true;
        }
        return false;
    }
    
    public function delete() {
        if (!$this->id) {
            throw new Exception("Cannot delete non-existent schedule");
        }
        
        $stmt = $this->db->prepare("DELETE FROM backup_schedules WHERE id = ?");
        return $stmt->execute([$this->id]);
    }
    
    public function canManage($username) {
        if (!$this->id) {
            return false;
        }
        
        // Root can manage all schedules
        if ($username === 'root') {
            return true;
        }
        
        // User can manage their own schedules
        return $this->data['user'] === $username;
    }
    
    public function getData() {
        return $this->data;
    }
    
    public function getId() {
        return $this->id;
    }
    
    public function updateLastRun() {
        if (!$this->id) {
            throw new Exception("Cannot update non-existent schedule");
        }
        
        $nextRun = $this->calculateNextRun($this->data['schedule_type'], $this->data['schedule_time'], $this->data['schedule_day']);
        
        $stmt = $this->db->prepare("UPDATE backup_schedules SET last_run_at = NOW(), next_run_at = ? WHERE id = ?");
        return $stmt->execute([$nextRun, $this->id]);
    }
    
    private function calculateNextRun($scheduleType, $scheduleTime, $scheduleDay = null) {
        $now = new DateTime();
        $time = new DateTime($scheduleTime);
        
        switch ($scheduleType) {
            case 'daily':
                $nextRun = new DateTime('tomorrow');
                $nextRun->setTime($time->format('H'), $time->format('i'), 0);
                break;
                
            case 'weekly':
                $dayOfWeek = $scheduleDay ?? 0; // Default to Sunday
                $nextRun = new DateTime('next ' . ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][$dayOfWeek]);
                $nextRun->setTime($time->format('H'), $time->format('i'), 0);
                break;
                
            case 'monthly':
                $dayOfMonth = $scheduleDay ?? 1; // Default to 1st
                $nextRun = new DateTime('first day of next month');
                $nextRun->setDate($nextRun->format('Y'), $nextRun->format('m'), min($dayOfMonth, $nextRun->format('t')));
                $nextRun->setTime($time->format('H'), $time->format('i'), 0);
                break;
                
            default:
                throw new Exception("Invalid schedule type: $scheduleType");
        }
        
        return $nextRun->format('Y-m-d H:i:s');
    }
    
    public static function listSchedules(PDO $db = null, $filters = []) {
        if ($db === null) {
            $mysql = new \mysqlmgmt();
            $db = $mysql->getMySQLConnection();
            $db->exec("USE whp");
        }
        
        $sql = "SELECT bs.*, bt.name as target_name, bt.type as target_type 
                FROM backup_schedules bs 
                JOIN backup_targets bt ON bs.target_id = bt.id 
                WHERE 1=1";
        $params = [];
        
        if (isset($filters['user'])) {
            $sql .= " AND bs.user = ?";
            $params[] = $filters['user'];
        }
        
        if (isset($filters['target_id'])) {
            $sql .= " AND bs.target_id = ?";
            $params[] = $filters['target_id'];
        }
        
        if (isset($filters['backup_type'])) {
            $sql .= " AND bs.backup_type = ?";
            $params[] = $filters['backup_type'];
        }
        
        if (isset($filters['is_active'])) {
            $sql .= " AND bs.is_active = ?";
            $params[] = $filters['is_active'];
        }
        
        $sql .= " ORDER BY bs.created_at DESC";
        
        if (isset($filters['limit'])) {
            $sql .= " LIMIT " . intval($filters['limit']);
            if (isset($filters['offset'])) {
                $sql .= " OFFSET " . intval($filters['offset']);
            }
        }
        
        $stmt = $db->prepare($sql);
        $stmt->execute($params);
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    
    public static function getDueSchedules(PDO $db = null) {
        if ($db === null) {
            $mysql = new \mysqlmgmt();
            $db = $mysql->getMySQLConnection();
            $db->exec("USE whp");
        }
        
        $sql = "SELECT bs.*, bt.name as target_name 
                FROM backup_schedules bs 
                JOIN backup_targets bt ON bs.target_id = bt.id 
                WHERE bs.is_active = 1 AND bs.next_run_at <= NOW()
                ORDER BY bs.next_run_at ASC";
        
        $stmt = $db->prepare($sql);
        $stmt->execute();
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}