<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Alerta;
use App\Models\Representante;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Schema;
use OpenSpout\Common\Entity\Row;
use OpenSpout\Common\Entity\Style\Color;
use OpenSpout\Common\Entity\Style\Style;
use OpenSpout\Writer\XLSX\Writer as XLSXWriter;

class AlertaController extends Controller
{
    public function config()
    {
        if (! Schema::hasTable('alertas_config')) {
            return response()->json([
                'habilitado' => false,
                'correo_destino' => null,
            ]);
        }

        $row = DB::table('alertas_config')->where('id_config', 1)->first();

        return response()->json([
            'habilitado' => (bool) ($row->habilitado ?? false),
            'correo_destino' => isset($row->correo_destino) && is_string($row->correo_destino) ? $row->correo_destino : null,
        ]);
    }

    public function updateConfig(Request $request)
    {
        if (! Schema::hasTable('alertas_config')) {
            return response()->json(['message' => 'Configuración de alertas no disponible. Ejecuta migraciones.'], 500);
        }

        $data = $request->validate([
            'habilitado' => ['required', 'boolean'],
            'correo_destino' => ['nullable', 'email', 'max:150'],
        ]);

        $habilitado = (bool) $data['habilitado'];
        $correo = array_key_exists('correo_destino', $data) && is_string($data['correo_destino'])
            ? trim($data['correo_destino'])
            : null;
        if ($correo === '') {
            $correo = null;
        }

        if ($habilitado && ! $correo) {
            return response()->json(['message' => 'Configura un correo válido para habilitar el envío.'], 422);
        }

        $now = now();
        $exists = DB::table('alertas_config')->where('id_config', 1)->exists();
        if ($exists) {
            DB::table('alertas_config')->where('id_config', 1)->update([
                'habilitado' => $habilitado ? 1 : 0,
                'correo_destino' => $correo,
                'fecha_actualizacion' => $now,
            ]);
        } else {
            DB::table('alertas_config')->insert([
                'id_config' => 1,
                'habilitado' => $habilitado ? 1 : 0,
                'correo_destino' => $correo,
                'fecha_creacion' => $now,
                'fecha_actualizacion' => $now,
            ]);
        }

        return $this->config();
    }

    public function index(Request $request)
    {
        $this->syncAlertasPorVencimiento();

        $query = Alerta::query()->with(['representante.institucion']);

        if ($request->filled('id_representante')) {
            $query->where('id_representante', $request->integer('id_representante'));
        }

        if ($request->filled('estado')) {
            $query->where('estado', $request->string('estado'));
        }

        if ($request->filled('tipo_alerta')) {
            $query->where('tipo_alerta', $request->string('tipo_alerta'));
        }

        return response()->json($query->orderByDesc('fecha_generada')->limit(500)->get());
    }

    public function export(Request $request)
    {
        $this->syncAlertasPorVencimiento();

        $query = Alerta::query()->with(['representante.institucion']);

        if ($request->filled('id_representante')) {
            $query->where('id_representante', $request->integer('id_representante'));
        }

        if ($request->filled('estado')) {
            $query->where('estado', $request->string('estado'));
        }

        if ($request->filled('tipo_alerta')) {
            $query->where('tipo_alerta', $request->string('tipo_alerta'));
        }

        $fileName = 'alertas.xlsx';

        return response()->streamDownload(function () use ($query) {
            $today = Carbon::today();

            $writer = new XLSXWriter();
            $writer->openToFile('php://output');
            $sheet = $writer->getCurrentSheet();
            $sheet->setName('Alertas');

            $headerStyle = (new Style())->setFontBold();
            $writer->addRow(Row::fromValues([
                'ID',
                'Tipo',
                'Estado',
                'Fecha objetivo',
                'Días restantes',
                'Fecha generada',
                'Fecha leída',
                'Representante',
                'Organismo',
            ], $headerStyle));

            $rowStyleEven = (new Style())->setBackgroundColor(Color::WHITE);
            $rowStyleOdd = (new Style())->setBackgroundColor(Color::rgb(243, 251, 255));
            $rowIndex = 0;

            $query->orderByDesc('fecha_generada')->chunk(500, function ($rows) use ($writer, $today, $rowStyleEven, $rowStyleOdd, &$rowIndex) {
                foreach ($rows as $row) {
                    $rowIndex++;
                    $style = $rowIndex % 2 === 0 ? $rowStyleEven : $rowStyleOdd;
                    $fechaObjetivo = (string) ($row->fecha_objetivo ?? '');
                    $diasRestantes = '';
                    if ($fechaObjetivo !== '') {
                        try {
                            $diasRestantes = (string) $today->diffInDays(Carbon::parse($fechaObjetivo), false);
                        } catch (\Throwable) {
                            $diasRestantes = '';
                        }
                    }

                    $repNombre = '';
                    if ($row->representante) {
                        $repNombre = trim((string) (($row->representante->nombres ?? '').' '.($row->representante->apellidos ?? '')));
                    }

                    $writer->addRow(Row::fromValues([
                        (string) ($row->id_alerta ?? ''),
                        (string) ($row->tipo_alerta ?? ''),
                        (string) ($row->estado ?? ''),
                        $fechaObjetivo,
                        $diasRestantes,
                        (string) ($row->fecha_generada ?? ''),
                        (string) ($row->fecha_leida ?? ''),
                        $repNombre,
                        (string) ($row->representante?->institucion?->nombre ?? ''),
                    ], $style));
                }
            });

            $sheet->setColumnWidth(10, 1);
            $sheet->setColumnWidth(14, 2);
            $sheet->setColumnWidth(14, 3);
            $sheet->setColumnWidth(16, 4);
            $sheet->setColumnWidth(16, 5);
            $sheet->setColumnWidth(20, 6);
            $sheet->setColumnWidth(20, 7);
            $sheet->setColumnWidth(28, 8);
            $sheet->setColumnWidth(30, 9);

            $writer->close();
        }, $fileName, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
    }

    public function dashboard()
    {
        $this->syncAlertasPorVencimiento();

        $pendientesPorTipoRows = Alerta::query()
            ->selectRaw('tipo_alerta, COUNT(*) as total')
            ->where('estado', 'pendiente')
            ->groupBy('tipo_alerta')
            ->get();

        $pendientesPorTipo = [
            '60_dias' => 0,
            '30_dias' => 0,
            '7_dias' => 0,
        ];

        foreach ($pendientesPorTipoRows as $row) {
            $tipo = (string) $row->tipo_alerta;
            $pendientesPorTipo[$tipo] = (int) $row->total;
        }

        $totalPendientes = array_sum($pendientesPorTipo);
        $totalLeidas = (int) Alerta::query()->where('estado', 'leida')->count();

        $recientes = Alerta::query()
            ->with(['representante.institucion'])
            ->orderByDesc('fecha_generada')
            ->limit(20)
            ->get();

        return response()->json([
            'stats' => [
                'total_pendientes' => $totalPendientes,
                'total_leidas' => $totalLeidas,
                'pendientes_por_tipo' => $pendientesPorTipo,
                'generated_at' => now()->toISOString(),
            ],
            'recent' => $recientes,
        ]);
    }

    public function show(Alerta $alerta)
    {
        return response()->json($alerta->load(['representante.institucion']));
    }

    public function update(Request $request, Alerta $alerta)
    {
        $data = $request->validate([
            'estado' => ['sometimes', 'required', 'in:pendiente,leida'],
        ]);

        $nuevoEstado = $data['estado'] ?? null;
        if ($nuevoEstado !== null) {
            $alerta->estado = $nuevoEstado;
            if ($nuevoEstado === 'leida' && $alerta->fecha_leida === null) {
                $alerta->fecha_leida = now();
            }
            if ($nuevoEstado === 'pendiente') {
                $alerta->fecha_leida = null;
            }
        }

        $alerta->save();

        return response()->json($alerta);
    }

    private function syncAlertasPorVencimiento(): void
    {
        $today = Carbon::today();
        $now = now();

        DB::table('representantes')
            ->where('estado', '!=', 'inactivo')
            ->whereNotNull('fecha_fin')
            ->whereDate('fecha_fin', '<', $today->toDateString())
            ->where('estado', '!=', 'vencido')
            ->update([
                'estado' => 'vencido',
                'fecha_actualizacion' => $now,
            ]);

        DB::table('representantes')
            ->where('estado', '=', 'vencido')
            ->whereNotNull('fecha_fin')
            ->whereDate('fecha_fin', '>=', $today->toDateString())
            ->update([
                'estado' => 'en_curso',
                'fecha_actualizacion' => $now,
            ]);

        $hasta = $today->copy()->addDays(60);

        $representantes = Representante::query()
            ->with(['institucion:id_institucion,nombre'])
            ->where('estado', '!=', 'inactivo')
            ->whereNotNull('fecha_fin')
            ->whereDate('fecha_fin', '>=', $today->toDateString())
            ->whereDate('fecha_fin', '<=', $hasta->toDateString())
            ->get(['id_representante', 'fecha_fin', 'nombres', 'apellidos', 'id_institucion']);

        $existing = DB::table('alertas')
            ->whereIn('id_representante', $representantes->pluck('id_representante'))
            ->whereDate('fecha_objetivo', '>=', $today->toDateString())
            ->whereDate('fecha_objetivo', '<=', $hasta->toDateString())
            ->get(['id_representante', 'tipo_alerta', 'fecha_objetivo']);

        $existingKeys = [];
        foreach ($existing as $row) {
            $existingKeys[$row->id_representante.'|'.$row->tipo_alerta.'|'.$row->fecha_objetivo] = true;
        }

        $rows = [];
        $newRows = [];
        foreach ($representantes as $representante) {
            $fechaFin = $representante->fecha_fin;
            if ($fechaFin === null) {
                continue;
            }

            $diasRestantes = $today->diffInDays(Carbon::parse($fechaFin), false);
            if ($diasRestantes < 0) {
                continue;
            }

            $tipos = [];
            if ($diasRestantes <= 60) {
                $tipos[] = '60_dias';
            }
            if ($diasRestantes <= 30) {
                $tipos[] = '30_dias';
            }
            if ($diasRestantes <= 7) {
                $tipos[] = '7_dias';
            }

            if (count($tipos) === 0) {
                continue;
            }

            foreach ($tipos as $tipo) {
                $row = [
                    'id_representante' => (int) $representante->getKey(),
                    'tipo_alerta' => $tipo,
                    'estado' => 'pendiente',
                    'fecha_objetivo' => Carbon::parse($fechaFin)->toDateString(),
                    'fecha_generada' => $now,
                    'fecha_leida' => null,
                ];
                $rows[] = $row;

                $key = $row['id_representante'].'|'.$row['tipo_alerta'].'|'.$row['fecha_objetivo'];
                if (! isset($existingKeys[$key])) {
                    $existingKeys[$key] = true;
                    $newRows[] = $row;
                }
            }
        }

        if (count($rows) > 0) {
            DB::table('alertas')->insertOrIgnore($rows);
        }

        if (count($newRows) > 0) {
            $this->notifyNewAlertasByEmail($newRows, $representantes, $today);
        }
    }

    private function notifyNewAlertasByEmail(array $newRows, $representantes, Carbon $today): void
    {
        if (! Schema::hasTable('alertas_config')) {
            return;
        }

        $cfg = DB::table('alertas_config')->where('id_config', 1)->first();
        $habilitado = (bool) ($cfg->habilitado ?? false);
        $correo = isset($cfg->correo_destino) && is_string($cfg->correo_destino) ? trim($cfg->correo_destino) : '';
        if (! $habilitado || $correo === '') {
            return;
        }

        $repById = [];
        foreach ($representantes as $r) {
            $repById[(int) $r->getKey()] = $r;
        }

        $lines = [];
        $lines[] = 'Se generaron nuevas alertas de vencimiento en ASUP:';
        $lines[] = '';

        foreach ($newRows as $row) {
            $idRep = (int) ($row['id_representante'] ?? 0);
            $tipo = (string) ($row['tipo_alerta'] ?? '');
            $fechaObjetivo = (string) ($row['fecha_objetivo'] ?? '');

            $rep = $repById[$idRep] ?? null;
            $repNombre = $rep ? trim((string) (($rep->apellidos ?? '').', '.($rep->nombres ?? ''))) : '#'.$idRep;
            $org = $rep?->institucion?->nombre ?? '—';

            $dias = '';
            if ($fechaObjetivo !== '') {
                try {
                    $dias = (string) $today->diffInDays(Carbon::parse($fechaObjetivo), false);
                } catch (\Throwable) {
                    $dias = '';
                }
            }

            $tipoLabel = match ($tipo) {
                '7_dias' => '7 días',
                '30_dias' => '30 días',
                '60_dias' => '60 días',
                default => $tipo,
            };

            $lines[] = "- {$tipoLabel} | {$repNombre} | {$org} | vence: {$fechaObjetivo}".($dias !== '' ? " | días restantes: {$dias}" : '');
        }

        $lines[] = '';
        $lines[] = 'Configuración: este correo se envía al destino configurado en el módulo Alertas.';

        $subject = 'ASUP - Nuevas alertas ('.count($newRows).')';
        $body = implode("\n", $lines);

        try {
            Mail::raw($body, function ($message) use ($correo, $subject) {
                $message->to($correo)->subject($subject);
            });
        } catch (\Throwable $e) {
            Log::error('No se pudo enviar correo de alertas', ['error' => $e->getMessage()]);
        }
    }
}
