<?php

/**
 * ============================================================
 *
 * @project   biiproject
 *
 * @author    Andika Debi Putra
 *
 * @email     andikadebiputra@gmail.com
 *
 * @website   https://biiproject.com
 *
 * @copyright Copyright (c) 2026 Andika Debi Putra
 * @license   Proprietary - All Rights Reserved
 *
 * @version   1.0.0
 *
 * @created   2026-05-01
 * ============================================================
 *
 * Unauthorized copying, modification, distribution, or use
 * of this file is strictly prohibited without prior written
 * permission from the author.
 * ============================================================
 */

namespace App\Services\System;

use App\Events\SystemNotification;
use App\Models\User;
use App\Notifications\SystemManagementNotification;
use App\Services\SystemConfig\SystemConfigService;
use Exception;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;

class MaintenanceManagementService
{
    public function __construct(
        protected SystemConfigService $configService
    ) {}

    /**
     * Sync the physical maintenance state with the database configuration.
     */
    public function syncState()
    {
        try {
            $settings = $this->configService->all();
            $enabled = filter_var($settings['maintenance_mode_enabled'] ?? false, FILTER_VALIDATE_BOOLEAN);
            $isCurrentlyDown = $this->isDown();

            if ($enabled) {
                $this->activateMaintenance($settings);

                // Only notify if it was NOT already down
                if (! $isCurrentlyDown) {
                    Notification::send(
                        User::permission('view notification center')->get(),
                        new SystemManagementNotification('Maintenance Active', 'System is entering Maintenance Mode.', 'warning')
                    );
                }
            } else {
                $this->deactivateMaintenance();

                // Only notify if it WAS previously down
                if ($isCurrentlyDown) {
                    Notification::send(
                        User::permission('view notification center')->get(),
                        new SystemManagementNotification('System Online', 'System is now LIVE and online.', 'success')
                    );
                }
            }

            return true;
        } catch (Exception $e) {
            Log::error('Maintenance Mode Sync Error: '.$e->getMessage());

            return false;
        }
    }

    /**
     * Activate Laravel's native maintenance mode with dynamic parameters.
     */
    protected function activateMaintenance(array $settings)
    {
        $options = [];

        // 1. Secret Bypass URL
        if (! empty($settings['maintenance_mode_secret'])) {
            $options['--secret'] = $settings['maintenance_mode_secret'];
        }

        // 2. Refresh (Browser refresh interval)
        $options['--refresh'] = 60; // Default 60 seconds

        // 3. Retry After Header
        if (! empty($settings['maintenance_mode_retry'])) {
            $options['--retry'] = (int) $settings['maintenance_mode_retry'];
        }

        // 4. Allowed IPs
        if (! empty($settings['maintenance_mode_allowed_ips'])) {
            // Convert textarea lines/commas to array
            $ips = preg_split('/[\s,]+/', $settings['maintenance_mode_allowed_ips'], -1, PREG_SPLIT_NO_EMPTY);
            if (! empty($ips)) {
                $options['--allow'] = $ips;
            }
        }

        // 5. Status Code (Always 503 for maintenance)
        $options['--status'] = 503;

        Log::info('System: Activating Maintenance Mode', $options);

        // Note: Laravel 11+ down command handles these options
        Artisan::call('down', $options);
    }

    /**
     * Deactivate maintenance mode.
     */
    protected function deactivateMaintenance()
    {
        if (app()->isDownForMaintenance()) {
            Log::info('System: Deactivating Maintenance Mode');
            Artisan::call('up');
        }
    }

    /**
     * Check if the system is currently in maintenance mode.
     */
    public function isDown(): bool
    {
        return app()->isDownForMaintenance();
    }

    /**
     * Automatically release maintenance mode if the end time has passed.
     */
    public function autoCheckAndRelease(): void
    {
        $settings = $this->configService->all();
        $enabled = filter_var($settings['maintenance_mode_enabled'] ?? false, FILTER_VALIDATE_BOOLEAN);
        $endAt = $settings['maintenance_mode_end_at'] ?? null;

        if (! $enabled || empty($endAt)) {
            return;
        }

        try {
            $endTime = new \DateTime($endAt);
            $now = new \DateTime;

            if ($now >= $endTime) {
                Log::info('System: Maintenance window expired. Automatically deactivating maintenance mode.', [
                    'expired_at' => $endAt,
                    'current_time' => $now->format('Y-m-d H:i:s'),
                ]);

                // Update configuration in DB
                $this->configService->update([
                    'maintenance_mode_enabled' => false,
                    'maintenance_mode_end_at' => null, // Optional: Clear the end time
                ]);

                // Physical release (artisan up)
                $this->syncState();
            }
        } catch (Exception $e) {
            Log::error('System: Automatic Maintenance Release failed: '.$e->getMessage());
        }
    }

    /**
     * Broadcast a real-time warning to all active users via WebSockets.
     */
    public function broadcastWarning(int $minutes)
    {
        $message = __('SYSTEM ALERT: The system will enter maintenance mode in :min minutes. Please save your work immediately.', ['min' => $minutes]);

        // 1. Broadcast event for real-time UI notification (WebSockets)
        event(new SystemNotification(
            message: $message,
            type: 'warning',
            title: __('Maintenance Warning')
        ));

        // 2. Persistent notification in the database
        Notification::send(
            User::all(), // Notify everyone
            new SystemManagementNotification('Scheduled Maintenance', $message, 'warning', 'Developer')
        );

        Log::info("System: Broadcasted maintenance warning (Starting in {$minutes}m).");

        return true;
    }
}
