<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Application;
use App\Services\ParticularApplicationPdf;
use App\Services\RadomiroPayrollAuthorizationPdf;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use App\Mail\ApplicationApprovedNotification;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpFoundation\Response;

class ApplicationAdminController extends Controller
{
    public function dashboard()
    {
        $total = Application::count();
        $currentMonth = Application::whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])->count();
        $previousMonth = Application::whereBetween('created_at', [now()->subMonth()->startOfMonth(), now()->subMonth()->endOfMonth()])->count();
        $trend = $previousMonth > 0 ? round((($currentMonth - $previousMonth) / $previousMonth) * 100) : ($currentMonth > 0 ? 100 : 0);

        return view('dashboard', [
            'kpis' => [
                'total' => $total,
                'pending' => Application::where('status', 'pending')->count(),
                'review' => Application::where('status', 'review')->count(),
                'approved' => Application::where('status', 'approved')->count(),
                'rejected' => Application::where('status', 'rejected')->count(),
                'month' => $currentMonth,
                'trend' => $trend,
                'approval_rate' => $total ? round(Application::where('status', 'approved')->count() / $total * 100) : 0,
            ],
            'types' => [
                'particular' => Application::where('type', 'particular')->count(),
                'radomiro' => Application::where('type', 'radomiro')->count(),
                'gabriela' => Application::where('type', 'gabriela')->count(),
                'club_golf' => Application::where('type', 'club_golf')->count(),
                'enaex' => Application::where('type', 'enaex')->count(),
            ],
            'recent' => Application::latest()->take(6)->get(),
        ]);
    }

    public function index(Request $request)
    {
        $query = Application::query()->latest();
        $query->when($request->filled('type'), fn ($q) => $q->where('type', $request->type));
        $query->when($request->filled('status'), fn ($q) => $q->where('status', $request->status));
        $query->when(
            $request->filled('month') && preg_match('/^\d{4}-(0[1-9]|1[0-2])$/', (string) $request->month),
            fn ($q) => $q
                ->whereYear('created_at', (int) substr((string) $request->month, 0, 4))
                ->whereMonth('created_at', (int) substr((string) $request->month, 5, 2))
        );
        $query->when($request->filled('search'), function ($q) use ($request) {
            $search = trim((string) $request->search);
            $escaped = addcslashes($search, '%_\\');
            $cleanRut = strtoupper(preg_replace('/[^0-9K]/i', '', $search));
            $q->where(fn ($sub) => $sub
                ->where('full_name', 'like', '%'.$escaped.'%')
                ->orWhere('folio', 'like', '%'.$escaped.'%')
                ->when(strlen($cleanRut) >= 8, fn ($rutQuery) => $rutQuery->orWhere('rut_hash', hash_hmac('sha256', $cleanRut, config('app.key'))))
            );
        });

        return view('admin.applications.index', [
            'applications' => $query->paginate(12)->withQueryString(),
            'counts' => ['total' => Application::count(), 'pending' => Application::where('status', 'pending')->count(), 'review' => Application::where('status', 'review')->count(), 'approved' => Application::where('status', 'approved')->count()],
        ]);
    }

    public function show(Application $application)
    {
        return view('admin.applications.show', compact('application'));
    }

    public function edit(Application $application)
    {
        return view('admin.applications.edit', compact('application'));
    }

    public function updateData(Request $request, Application $application)
    {
        $validated = $request->validate([
            'full_name' => ['required', 'string', 'max:160'], 'rut' => ['required', 'string', 'max:12'],
            'birth_date' => ['required', 'date', 'before:today'], 'email' => ['required', 'email', 'max:160'],
            'phone' => ['required', 'string', 'max:30'], 'address' => ['required', 'string', 'max:255'],
            'delivery_address' => [Rule::requiredIf($application->type !== 'particular'), 'nullable', 'string', 'max:255'],
            'profession' => ['nullable', 'string', 'max:160'], 'work_area' => ['nullable', 'string', 'max:160'],
            'company' => ['nullable', 'string', 'max:160'], 'job_title' => ['nullable', 'string', 'max:160'],
            'superintendency' => ['nullable', 'string', 'max:160'], 'work_phone' => ['nullable', 'string', 'max:30'],
            'management' => ['nullable', 'string', 'max:160'], 'work_email' => ['nullable', 'email', 'max:160'],
            'recommender_name' => ['nullable', 'string', 'max:160'], 'recommender_rut' => ['nullable', 'string', 'max:12'],
            'signature_date' => ['required', 'date'],
            'dependents' => ['array', 'max:20'], 'dependents.*.full_name' => ['required', 'string', 'max:160'],
            'dependents.*.rut' => ['required', 'string', 'max:12'], 'dependents.*.birth_date' => ['required', 'date'],
            'dependents.*.relationship' => ['required', 'string', 'max:80'],
            'board_members' => ['array', 'max:20'], 'board_members.*.name' => ['nullable', 'string', 'max:160'],
            'board_members.*.rut' => ['nullable', 'string', 'max:12'], 'board_signatures.*' => ['nullable', 'image', 'mimes:jpg,jpeg,png', 'max:5120'],
        ]);

        $data = $application->data;
        foreach (['full_name','rut','birth_date','email','phone','address','delivery_address','profession','company','job_title','work_area','superintendency','work_phone','management','work_email','recommender_name','recommender_rut','signature_date'] as $key) {
            $data[$key] = $validated[$key] ?? null;
        }
        $data['dependents'] = array_values($validated['dependents'] ?? []);
        $oldMembers = $data['board_members'] ?? [];
        $data['board_members'] = array_values($validated['board_members'] ?? []);
        foreach ($data['board_members'] as $index => &$member) {
            $member['signature'] = $oldMembers[$index]['signature'] ?? '';
            if ($request->hasFile("board_signatures.$index")) {
                $file = $request->file("board_signatures.$index");
                $member['signature'] = 'data:'.$file->getMimeType().';base64,'.base64_encode(file_get_contents($file->getRealPath()));
            }
        }
        unset($member);
        $application->update(['full_name' => $validated['full_name'], 'rut' => $validated['rut'], 'email' => $validated['email'], 'phone' => $validated['phone'], 'data' => $data]);
        return redirect()->route('admin.applications.show', $application)->with('status', 'Datos de la solicitud actualizados.');
    }

    public function update(Request $request, Application $application)
    {
        $validated = $request->validate([
            'status' => ['required', Rule::in(['pending', 'review', 'approved', 'rejected'])],
            'admin_notes' => ['nullable', 'string', 'max:2000'],
            'application_date' => ['nullable', 'date'],
            'payment_amount' => ['nullable', 'string', 'max:80'],
            'receipt_number' => ['nullable', 'string', 'max:80'],
            'first_payment_date' => ['nullable', 'date'],
            'payroll_received_by' => [Rule::requiredIf(in_array($application->type, ['radomiro', 'gabriela'], true) && $request->input('status') === 'approved'), 'nullable', 'string', 'max:160'],
            'payroll_stamp' => ['nullable', 'image', 'mimes:jpg,jpeg,png', 'max:5120'],
        ]);

        $wasApproved = $application->status === 'approved';
        $updates = collect($validated)->only(['status', 'admin_notes'])->all();
        if (! empty($validated['application_date'])) {
            $updates['application_date'] = $validated['application_date'];
        }
        $data = $application->data;
        foreach (['application_date', 'payment_amount', 'receipt_number', 'first_payment_date'] as $key) {
            $data[$key] = $validated[$key] ?? null;
        }
        $updates['data'] = $data;
        if (in_array($application->type, ['radomiro', 'gabriela'], true) && $validated['status'] === 'approved') {
            $data['payroll_received_by'] = $validated['payroll_received_by'];
            $data['payroll_received_at'] = $data['payroll_received_at'] ?? now()->toIso8601String();
            if ($request->hasFile('payroll_stamp')) {
                $file = $request->file('payroll_stamp');
                $data['payroll_stamp'] = 'data:'.$file->getMimeType().';base64,'.base64_encode(file_get_contents($file->getRealPath()));
            }
            $updates['data'] = $data;
        }
        $application->update($updates);
        if (! $wasApproved && $application->status === 'approved') {
            try {
                Mail::to($application->email)->send(new ApplicationApprovedNotification($application, config('mail.transfer')));
            } catch (\Throwable $exception) {
                Log::error('No se pudo enviar la notificación de aprobación.', ['application_id' => $application->id, 'error' => $exception->getMessage()]);
            }
        }
        return back()->with('status', 'Solicitud actualizada.');
    }

    public function attachment(Application $application, int $index): StreamedResponse
    {
        $file = $application->attachments[$index] ?? abort(404);
        abort_unless(isset($file['path'], $file['name']) && Storage::disk('local')->exists($file['path']), 404);
        if (request()->boolean('preview')) {
            return Storage::disk('local')->response($file['path'], $file['name'], [
                'Content-Type' => $file['type'] ?? 'application/octet-stream',
                'X-Content-Type-Options' => 'nosniff',
            ]);
        }
        return Storage::disk('local')->download($file['path'], $file['name'], [
            'Content-Type' => $file['type'] ?? 'application/octet-stream',
            'X-Content-Type-Options' => 'nosniff',
        ]);
    }

    public function pdf(Request $request, Application $application, ParticularApplicationPdf $generator): Response
    {
        abort_unless(in_array($application->type, ['particular', 'radomiro', 'gabriela', 'club_golf', 'enaex'], true), 404);

        $preview = $request->boolean('preview');
        $grid = app()->isLocal() && $request->boolean('grid');
        $contents = $generator->generate($application, $grid);
        $filename = "Inscripcion_{$application->folio}.pdf";

        return response($contents, 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => ($preview ? 'inline' : 'attachment').'; filename="'.$filename.'"',
            'Content-Length' => (string) strlen($contents),
            'X-Content-Type-Options' => 'nosniff',
            'Cache-Control' => 'no-store, private',
        ]);
    }

    public function radomiroAuthorization(Request $request, Application $application, RadomiroPayrollAuthorizationPdf $generator): Response
    {
        abort_unless($application->type === 'radomiro', 404);
        $contents = $generator->generate($application);
        return response($contents, 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => ($request->boolean('preview') ? 'inline' : 'attachment').'; filename="Autorizacion_'.$application->folio.'.pdf"',
            'Content-Length' => (string) strlen($contents), 'X-Content-Type-Options' => 'nosniff', 'Cache-Control' => 'no-store, private',
        ]);
    }

    public function gabrielaAuthorization(Request $request, Application $application, RadomiroPayrollAuthorizationPdf $generator): Response
    {
        abort_unless($application->type === 'gabriela', 404);
        $contents = $generator->generate($application);
        return response($contents, 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => ($request->boolean('preview') ? 'inline' : 'attachment').'; filename="Autorizacion_'.$application->folio.'.pdf"',
            'Content-Length' => (string) strlen($contents), 'X-Content-Type-Options' => 'nosniff', 'Cache-Control' => 'no-store, private',
        ]);
    }
}
