<?php

namespace App\Http\Controllers;

use Carbon\Carbon;
use Illuminate\Foundation\Application;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
use App\Models\Scawatt;
use App\Models\Granja;
use App\Models\Usuario;
use App\Models\Marketplace;
use App\Models\SolicitudContactoScawatt;
use App\Models\Deposito;
use App\Models\Retiro;

class MonitorController extends Controller
{
    /**
     * Mostrar página de monitor
     */
    public function index()
    {
        return view('monitor.index');
    }

    /**
     * Obtener el estado de procesos y detalles del servidor.
     */
    public function obtenerProcesos(): JsonResponse
    {
        try {
            $tokensPath = '/home/scalarapp/scalar-data/scawatt-server/produccion-scawatts/data_scawatts/raiz-scawatt/scawatts_tokens.json';
            $publicJsonPath = '/home/scalarapp/public_html/develop/code-test/ScaWatt.json';

            $procesos = [
                'monitor_scawatt' => $this->checkProcess('monitor_scawatt'),
                'sincronizacion' => $this->checkFileIsFresh($tokensPath, 120),
                'cron_tasks' => $this->checkProcess('cron'),
                'mysql_db' => $this->checkDatabaseConnection(),
            ];

            $detalles = [
                'servidor' => gethostname() ?: php_uname('n'),
                'usuario' => get_current_user(),
                'timestamp' => now()->toDateTimeString(),
                'uptime' => $this->getSystemUptime(),
                'php_version' => PHP_VERSION,
                'laravel_version' => Application::VERSION,
            ];

            $archivos = [
                'scawatts_tokens' => $this->fileStatus($tokensPath, 120),
                'scawatt_public' => $this->fileStatus($publicJsonPath, 120),
            ];

            $metricas = $this->obtenerMetricasSistema();
            $dashboard = $this->obtenerResumenDashboard($metricas, $archivos['scawatts_tokens'] ?? null);
            $solicitudes = $this->obtenerResumenSolicitudes();

            return response()->json([
                'success' => true,
                'procesos' => $procesos,
                'detalles' => $detalles,
                'archivos' => $archivos,
                'metricas' => $metricas,
                'dashboard' => $dashboard,
                'solicitudes' => $solicitudes,
            ]);
        } catch (\Throwable $exception) {
            Log::error('MonitorController::obtenerProcesos error', [
                'message' => $exception->getMessage(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'No se pudo obtener el estado del monitor.',
            ], 500);
        }
    }

    private function obtenerMetricasSistema(): array
    {
        $totalesScawatt = Scawatt::selectRaw('
                COUNT(*) as total,
                COALESCE(SUM(valor_actual), 0) as valor_actual_total,
                COALESCE(SUM(valor_inicial), 0) as valor_inicial_total,
                COALESCE(SUM(valor_actual - valor_inicial), 0) as valorizacion_total
            ')
            ->first();

        $valorActualTotal = (float) ($totalesScawatt->valor_actual_total ?? 0);
        $valorInicialTotal = (float) ($totalesScawatt->valor_inicial_total ?? 0);
        $valorizacionTotal = (float) ($totalesScawatt->valorizacion_total ?? ($valorActualTotal - $valorInicialTotal));

        return [
            'scawatts_total' => (int) ($totalesScawatt->total ?? 0),
            'usuarios_total' => (int) Usuario::count(),
            'usuarios_con_scawatts' => (int) Scawatt::distinct('usuario_id')->count('usuario_id'),
            'granjas_total' => (int) Granja::count(),
            'capacidad_total_mw' => (float) Granja::sum('capacidad_mw'),
            'valor_actual_total' => $valorActualTotal,
            'valor_inicial_total' => $valorInicialTotal,
            'valorizacion_total' => $valorizacionTotal,
            'valoracion_porcentaje' => $valorInicialTotal > 0
                ? round(($valorizacionTotal / $valorInicialTotal) * 100, 2)
                : 0,
            'marketplace_en_venta' => (int) Marketplace::where('estado', 'en_venta')->count(),
            'marketplace_total' => (int) Marketplace::count(),
            'depositos_pendientes' => (int) Deposito::whereIn('estado', ['pendiente', 'en_proceso'])->count(),
            'retiros_pendientes' => (int) Retiro::whereIn('estado', ['pendiente', 'en_proceso'])->count(),
        ];
    }

    private function obtenerResumenDashboard(array $metricas, ?array $archivoTokens): array
    {
        return [
            'total_scawatts' => $metricas['scawatts_total'] ?? 0,
            'total_granjas' => $metricas['granjas_total'] ?? 0,
            'total_usuarios' => $metricas['usuarios_total'] ?? 0,
            'valor_actual_total' => $metricas['valor_actual_total'] ?? 0,
            'valorizacion_total' => $metricas['valorizacion_total'] ?? 0,
            'porcentaje_valorizacion' => $metricas['valoracion_porcentaje'] ?? 0,
            'capacidad_total_mw' => $metricas['capacidad_total_mw'] ?? 0,
            'marketplace_publicaciones_en_venta' => $metricas['marketplace_en_venta'] ?? 0,
            'depositos_pendientes' => $metricas['depositos_pendientes'] ?? 0,
            'retiros_pendientes' => $metricas['retiros_pendientes'] ?? 0,
            'ultima_sync' => $archivoTokens['last_modified'] ?? null,
        ];
    }

    private function obtenerResumenSolicitudes(): array
    {
        $pendientes = SolicitudContactoScawatt::pendientes()->count();
        $recientes = SolicitudContactoScawatt::orderByDesc('created_at')
            ->limit(20)
            ->get()
            ->map(function (SolicitudContactoScawatt $solicitud) {
                return [
                    'id' => $solicitud->id,
                    'nombre_completo' => $solicitud->nombre_completo,
                    'cedula' => $solicitud->cedula,
                    'email' => $solicitud->email,
                    'telefono' => $solicitud->telefono,
                    'cantidad_scawatts' => $solicitud->cantidad_scawatts,
                    'presupuesto_aproximado' => $solicitud->presupuesto_aproximado,
                    'mensaje' => $solicitud->mensaje,
                    'estado' => $solicitud->estado,
                    'created_at' => optional($solicitud->created_at)->toDateTimeString(),
                ];
            });

        return [
            'pendientes' => (int) $pendientes,
            'total' => (int) SolicitudContactoScawatt::count(),
            'recientes' => $recientes,
            'acciones_habilitadas' => false,
        ];
    }

    /**
     * Determina si un proceso está activo utilizando pgrep.
     */
    private function checkProcess(string $pattern): string
    {
        $output = [];
        $status = 1;
        @exec('pgrep -f ' . escapeshellarg($pattern), $output, $status);

        return $status === 0 && !empty($output) ? 'activo' : 'inactivo';
    }

    /**
     * Considera activo el proceso de sincronización si el archivo asociado es reciente.
     */
    private function checkFileIsFresh(string $path, int $maxMinutes): string
    {
        $status = $this->fileStatus($path, $maxMinutes);

        return $status['exists'] && $status['status'] === 'reciente' ? 'activo' : 'inactivo';
    }

    /**
     * Verifica el estado de un archivo relevante para el monitor.
     */
    private function fileStatus(string $path, int $maxMinutes): array
    {
        if (!file_exists($path)) {
            return [
                'exists' => false,
                'status' => 'faltante',
                'last_modified' => null,
                'age_minutes' => null,
                'size_bytes' => null,
                'path' => $path,
            ];
        }

        $lastModified = Carbon::createFromTimestamp(filemtime($path));
        $ageMinutes = $lastModified->diffInMinutes(now());

        return [
            'exists' => true,
            'status' => $ageMinutes <= $maxMinutes ? 'reciente' : 'desactualizado',
            'last_modified' => $lastModified->toDateTimeString(),
            'age_minutes' => $ageMinutes,
            'size_bytes' => filesize($path),
            'path' => $path,
        ];
    }

    /**
     * Verifica la conexión a la base de datos.
     */
    private function checkDatabaseConnection(): string
    {
        try {
            DB::connection()->getPdo();
            return 'activo';
        } catch (\Throwable $exception) {
            Log::warning('MonitorController::checkDatabaseConnection falló', [
                'message' => $exception->getMessage(),
            ]);
            return 'inactivo';
        }
    }

    /**
     * Obtiene una cadena amigable con el uptime del sistema.
     */
    private function getSystemUptime(): ?string
    {
        $uptimeFile = '/proc/uptime';

        if (!is_readable($uptimeFile)) {
            return null;
        }

        $content = trim((string) file_get_contents($uptimeFile));
        if ($content === '') {
            return null;
        }

        $seconds = (int) floor((float) explode(' ', $content)[0] ?? 0);

        if ($seconds <= 0) {
            return null;
        }

        $days = intdiv($seconds, 86400);
        $hours = intdiv($seconds % 86400, 3600);
        $minutes = intdiv($seconds % 3600, 60);

        $parts = [];
        if ($days > 0) {
            $parts[] = $days . 'd';
        }
        if ($hours > 0) {
            $parts[] = $hours . 'h';
        }
        if ($minutes > 0) {
            $parts[] = $minutes . 'm';
        }

        return empty($parts) ? $seconds . 's' : implode(' ', $parts);
    }
}
