<?php

namespace App\Http\Controllers;

use App\Exports\PersonerosExport;
use App\Exports\PersonerosTemplateExport;
use App\Imports\PersonerosImport;
use App\Models\Personero;
use App\Models\User;
use App\Models\VotingTable;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Facades\Excel;

class PersoneroController extends Controller
{
    public function index(Request $request): JsonResponse
    {
        $personeros = Personero::with([
            'politicalParty',
            'department',
            'province',
            'district',
            'votingLocation.district.province.department',
            'votingTable.votingLocation.district.province.department',
        ])
            ->ofParty($request->input('political_party_id'))
            ->ofStatus($request->input('status'))
            ->ofScope($request->input('scope'))
            ->ofAttendance($request->input('attendance'))
            ->atLocation($request->input('voting_location_id'))
            ->inDepartment($request->input('department_id'))
            ->ofFunction($request->input('function'))
            ->search($request->input('search'))
            ->orderBy('last_name')
            ->orderBy('first_name')
            ->paginate($request->integer('per_page', 15));

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

    public function store(Request $request): JsonResponse
    {
        $data = $request->validate([
            'political_party_id' => 'required|exists:political_parties,id',
            'voting_table_id' => 'nullable|exists:voting_tables,id',
            'department_id' => 'nullable|exists:departments,id',
            'province_id' => 'nullable|exists:provinces,id',
            'district_id' => 'nullable|exists:districts,id',
            'voting_location_id' => 'nullable|exists:voting_locations,id',
            'first_name' => 'required|string|max:255',
            'last_name' => 'required|string|max:255',
            'dni' => 'required|string|size:8|unique:personeros,dni',
            'phone' => 'nullable|string|max:20',
            'function' => 'required|in:titular,alterno,de_local',
            'scope' => 'required|in:departamental,provincial,distrital,local,mesa',
            'status' => 'sometimes|in:active,inactive',
            'attendance' => 'sometimes|in:pending,present,absent',
            'observations' => 'nullable|string|max:1000',
        ]);

        $personero = DB::transaction(function () use ($data) {
            $tempPassword = strtoupper(substr(bin2hex(random_bytes(4)), 0, 8));

            $user = User::create([
                'name' => $data['first_name'] . ' ' . $data['last_name'],
                'email' => $data['dni'] . '@personero.local',
                'password' => Hash::make($tempPassword),
                'role' => 'personero',
                'must_change_password' => true,
                'temp_password' => $tempPassword,
            ]);

            $data['user_id'] = $user->id;

            $personero = Personero::create($data);
            $personero->_temp_password = $tempPassword;

            return $personero;
        });

        $personero->load([
            'politicalParty',
            'department',
            'province',
            'district',
            'votingLocation.district.province.department',
            'votingTable.votingLocation.district.province.department',
        ]);

        $responseData = $personero->toArray();
        $responseData['temp_password'] = $personero->_temp_password ?? null;

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

    public function show(Personero $personero): JsonResponse
    {
        $personero->load([
            'politicalParty',
            'department',
            'province',
            'district',
            'votingLocation.district.province.department',
            'votingTable.votingLocation.district.province.department',
        ]);

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

    public function update(Request $request, Personero $personero): JsonResponse
    {
        $data = $request->validate([
            'political_party_id' => 'required|exists:political_parties,id',
            'voting_table_id' => 'nullable|exists:voting_tables,id',
            'department_id' => 'nullable|exists:departments,id',
            'province_id' => 'nullable|exists:provinces,id',
            'district_id' => 'nullable|exists:districts,id',
            'voting_location_id' => 'nullable|exists:voting_locations,id',
            'first_name' => 'required|string|max:255',
            'last_name' => 'required|string|max:255',
            'dni' => 'required|string|size:8|unique:personeros,dni,' . $personero->id,
            'phone' => 'nullable|string|max:20',
            'function' => 'required|in:titular,alterno,de_local',
            'scope' => 'required|in:departamental,provincial,distrital,local,mesa',
            'status' => 'sometimes|in:active,inactive',
            'attendance' => 'sometimes|in:pending,present,absent',
            'observations' => 'nullable|string|max:1000',
        ]);

        DB::transaction(function () use ($personero, $data) {
            $personero->update($data);

            if ($personero->user) {
                $userUpdates = [
                    'name' => $data['first_name'] . ' ' . $data['last_name'],
                ];
                if ($personero->user->email !== $data['dni'] . '@personero.local') {
                    $userUpdates['email'] = $data['dni'] . '@personero.local';
                }
                $personero->user->update($userUpdates);
            }
        });

        $personero->load([
            'politicalParty',
            'department',
            'province',
            'district',
            'votingLocation.district.province.department',
            'votingTable.votingLocation.district.province.department',
        ]);

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

    public function destroy(Personero $personero): JsonResponse
    {
        DB::transaction(function () use ($personero) {
            if ($personero->user) {
                $personero->user->tokens()->delete();
                $personero->user->delete();
            }
            $personero->delete();
        });

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

    public function export()
    {
        return Excel::download(new PersonerosExport, 'personeros.xlsx');
    }

    public function template()
    {
        return Excel::download(new PersonerosTemplateExport, 'plantilla_personeros.xlsx');
    }

    public function import(Request $request): JsonResponse
    {
        $request->validate([
            'file' => 'required|file|mimes:xlsx,xls,csv',
        ]);

        $import = new PersonerosImport;
        Excel::import($import, $request->file('file'));

        return response()->json([
            'imported' => $import->getImportedCount(),
            'errors' => $import->getErrors(),
        ]);
    }

    public function stats(): JsonResponse
    {
        $totalTables = VotingTable::count();
        $tablesWithPersonero = VotingTable::whereHas('personeros')->count();
        $tablesWithoutPersonero = $totalTables - $tablesWithPersonero;

        $totalPersoneros = Personero::count();
        $activePersoneros = Personero::where('status', 'active')->count();
        $inactivePersoneros = $totalPersoneros - $activePersoneros;

        $attendancePresent = Personero::where('attendance', 'present')->count();
        $attendanceAbsent = Personero::where('attendance', 'absent')->count();
        $attendancePending = Personero::where('attendance', 'pending')->count();

        $byScope = Personero::select('scope', DB::raw('count(*) as total'))
            ->groupBy('scope')
            ->pluck('total', 'scope');

        $byDepartment = Personero::select('departments.name as department', DB::raw('count(personeros.id) as total'))
            ->join('departments', 'personeros.department_id', '=', 'departments.id')
            ->whereNotNull('personeros.department_id')
            ->groupBy('departments.name')
            ->orderByDesc('total')
            ->limit(10)
            ->pluck('total', 'department');

        return response()->json([
            'total_tables' => $totalTables,
            'tables_with_personero' => $tablesWithPersonero,
            'tables_without_personero' => $tablesWithoutPersonero,
            'total_personeros' => $totalPersoneros,
            'active_personeros' => $activePersoneros,
            'inactive_personeros' => $inactivePersoneros,
            'attendance' => [
                'present' => $attendancePresent,
                'absent' => $attendanceAbsent,
                'pending' => $attendancePending,
            ],
            'by_scope' => $byScope,
            'by_department' => $byDepartment,
        ]);
    }

    public function updateAttendance(Request $request, Personero $personero): JsonResponse
    {
        $data = $request->validate([
            'attendance' => 'required|in:pending,present,absent',
        ]);

        $personero->update($data);

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

    /**
     * Reset a personero's password to a new temporary one.
     */
    public function resetPassword(Personero $personero): JsonResponse
    {
        if (!$personero->user) {
            return response()->json(['message' => 'Este personero no tiene usuario asociado.'], 404);
        }

        $tempPassword = strtoupper(substr(bin2hex(random_bytes(4)), 0, 8));

        $personero->user->update([
            'password' => Hash::make($tempPassword),
            'must_change_password' => true,
            'temp_password' => $tempPassword,
        ]);

        return response()->json([
            'message' => 'Contraseña restablecida correctamente.',
            'temp_password' => $tempPassword,
        ]);
    }
}
