<?php

namespace App\Http\Controllers;

use App\Exports\CandidatesExport;
use App\Models\Candidate;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Facades\Excel;

class CandidateController extends Controller
{
    private const VALID_TYPES = [
        'presidential',
        'national_senator',
        'regional_senator',
        'regional_deputy',
        'andean_parliament',
    ];

    private const REGIONAL_TYPES = ['regional_senator', 'regional_deputy'];
    private const NUMBERED_TYPES = [
        'national_senator',
        'regional_senator',
        'regional_deputy',
        'andean_parliament',
    ];

    public function index(Request $request): JsonResponse
    {
        $request->validate([
            'type' => ['required', Rule::in(self::VALID_TYPES)],
        ]);

        $candidates = Candidate::with(['politicalParty', 'department'])
            ->ofType($request->type)
            ->ofParty($request->input('political_party_id'))
            ->ofDepartment($request->input('department_id'))
            ->search($request->input('search'))
            ->orderBy('political_party_id')
            ->orderBy('number')
            ->paginate($request->integer('per_page', 15));

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

    public function store(Request $request): JsonResponse
    {
        $data = $this->validateCandidate($request);

        if ($request->hasFile('photo')) {
            $data['photo'] = $request->file('photo')->store('candidates', 'public');
        }

        $candidate = Candidate::create($data);
        $candidate->load(['politicalParty', 'department']);

        return response()->json($candidate, 201);
    }

    public function show(Candidate $candidate): JsonResponse
    {
        $candidate->load(['politicalParty', 'department']);

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

    public function update(Request $request, Candidate $candidate): JsonResponse
    {
        $data = $this->validateCandidate($request);

        if ($request->hasFile('photo')) {
            if ($candidate->photo) {
                Storage::disk('public')->delete($candidate->photo);
            }
            $data['photo'] = $request->file('photo')->store('candidates', 'public');
        }

        $candidate->update($data);
        $candidate->load(['politicalParty', 'department']);

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

    public function destroy(Candidate $candidate): JsonResponse
    {
        if ($candidate->photo) {
            Storage::disk('public')->delete($candidate->photo);
        }

        $candidate->delete();

        return response()->json(null, 204);
    }

    public function export(Request $request)
    {
        $type = $request->input('type', 'presidential');
        if (!in_array($type, self::VALID_TYPES)) {
            return response()->json(['message' => 'Tipo de candidato inválido.'], 422);
        }
        $types = [
            'presidential' => 'presidenciales',
            'national_senator' => 'senadores_nacionales',
            'regional_senator' => 'senadores_regionales',
            'regional_deputy' => 'diputados_regionales',
            'andean_parliament' => 'parlamento_andino',
        ];
        return Excel::download(new CandidatesExport($type), "candidatos_{$types[$type]}.xlsx");
    }

    private function validateCandidate(Request $request): array
    {
        $type = $request->input('type');

        $rules = [
            'type' => ['required', Rule::in(self::VALID_TYPES)],
            'political_party_id' => 'required|exists:political_parties,id',
            'first_name' => 'required|string|max:255',
            'last_name' => 'required|string|max:255',
            'photo' => 'nullable|image|max:2048',
        ];

        if (in_array($type, self::NUMBERED_TYPES)) {
            $rules['number'] = 'required|integer|min:1';
        } else {
            $rules['number'] = 'nullable';
        }

        if (in_array($type, self::REGIONAL_TYPES)) {
            $rules['department_id'] = 'required|exists:departments,id';
        } else {
            $rules['department_id'] = 'nullable';
        }

        return $request->validate($rules);
    }
}
