<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Database;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;

class TeacherContractController
{
    private Connection $db;

    public function __construct()
    {
        try {
            $this->db = Database::getConnection();
        } catch (\Throwable $e) {
            error_log("Failed to get DB connection in TeacherContractController: " . $e->getMessage());
            http_response_code(500);
            echo json_encode(['error' => 'Internal Server Error - DB Connection']);
            exit;
        }
    }

    /**
     * Mostra un elenco di contratti con nomi associati.
     * GET /api/teacher-contracts
     * Accetta query params: teacher_id, school_year_id, structure_id
     */
    public function index(): void
    {
        try {
            $queryBuilder = $this->db->createQueryBuilder()
                ->select(
                    'tc.id', 'tc.teacher_id', 'tc.school_year_id', 'tc.structure_id',
                    'tc.contract_type', 'tc.start_date', 'tc.end_date', 'tc.weekly_hours', 'tc.salary',
                    't.first_name AS teacher_first_name', 't.last_name AS teacher_last_name',
                    'sy.name AS school_year_name',
                    's.name AS structure_name'
                )
                ->from('teacher_contracts', 'tc')
                ->leftJoin('tc', 'teachers', 't', 'tc.teacher_id = t.id')
                ->leftJoin('tc', 'school_years', 'sy', 'tc.school_year_id = sy.id')
                ->leftJoin('tc', 'structures', 's', 'tc.structure_id = s.id')
                ->orderBy('tc.start_date', 'DESC');

            // Filtri opzionali
            if (!empty($_GET['teacher_id'])) {
                $queryBuilder->andWhere('tc.teacher_id = :teacherId')
                             ->setParameter('teacherId', $_GET['teacher_id']);
            }
            if (!empty($_GET['school_year_id'])) {
                $queryBuilder->andWhere('tc.school_year_id = :schoolYearId')
                             ->setParameter('schoolYearId', $_GET['school_year_id']);
            }
             if (!empty($_GET['structure_id'])) {
                $queryBuilder->andWhere('tc.structure_id = :structureId')
                             ->setParameter('structureId', $_GET['structure_id']);
            }

            $contracts = $queryBuilder->fetchAllAssociative();

            echo json_encode($contracts);
        } catch (\Throwable $e) {
            http_response_code(500);
            error_log("Error fetching teacher contracts: " . $e->getMessage());
            echo json_encode(['error' => 'Failed to fetch teacher contracts']);
        }
    }

    /**
     * Mostra un contratto specifico con nomi associati.
     * GET /api/teacher-contracts/{id}
     */
    public function show(array $vars): void
    {
        $id = $vars['id'] ?? null;
        if ($id === null) {
             http_response_code(400); echo json_encode(['error' => 'Missing contract ID']); return;
        }

        try {
             $queryBuilder = $this->db->createQueryBuilder()
                ->select(
                    'tc.*',
                    't.first_name AS teacher_first_name', 't.last_name AS teacher_last_name',
                    'sy.name AS school_year_name',
                    's.name AS structure_name'
                )
                ->from('teacher_contracts', 'tc')
                ->leftJoin('tc', 'teachers', 't', 'tc.teacher_id = t.id')
                ->leftJoin('tc', 'school_years', 'sy', 'tc.school_year_id = sy.id')
                ->leftJoin('tc', 'structures', 's', 'tc.structure_id = s.id')
                ->where('tc.id = :id')
                ->setParameter('id', $id);

            $contract = $queryBuilder->fetchAssociative();

            if ($contract === false) {
                http_response_code(404);
                echo json_encode(['error' => "Teacher contract with ID {$id} not found"]);
            } else {
                echo json_encode($contract);
            }
        } catch (\Throwable $e) {
            http_response_code(500);
            error_log("Error fetching teacher contract {$id}: " . $e->getMessage());
            echo json_encode(['error' => 'Failed to fetch teacher contract']);
        }
    }

    /**
     * Crea un nuovo contratto.
     * POST /api/teacher-contracts
     */
    public function store(): void
    {
        // Leggi il corpo JSON della richiesta
        $input = json_decode(file_get_contents('php://input'), true);
        // Verifica se il JSON è valido e se è un array
        if (json_last_error() !== JSON_ERROR_NONE || !is_array($input)) {
             http_response_code(400);
             echo json_encode(['error' => 'Invalid JSON input']);
             return;
        }

        // Validazione campi obbligatori
        if (empty($input['teacher_id']) || empty($input['school_year_id']) || empty($input['start_date'])) {
            http_response_code(400);
            echo json_encode(['error' => 'Missing required fields: teacher_id, school_year_id, start_date']);
            return;
        }
        // Validazione date rimossa - affidata a frontend/DB constraint
        error_log(json_encode($input));
        $dataToInsert = [
            'teacher_id' => $input['teacher_id'],
            'school_year_id' => $input['school_year_id'],
            'structure_id' => (isset($input['structure_id']) && $input['structure_id'] !== '' && $input['structure_id'] !== null) ? (int)$input['structure_id'] : null,
            'contract_type' => $input['contract_type'] ?? null,
            'start_date' => $input['start_date'],
            'end_date' => (isset($input['end_date']) && $input['end_date'] !== '') ? $input['end_date'] : null, // Forza null se vuoto/non presente
            'weekly_hours' => (isset($input['weekly_hours']) && $input['weekly_hours'] !== '') ? (float)$input['weekly_hours'] : null, // Forza null se vuoto/non presente
            'salary' => (isset($input['salary']) && $input['salary'] !== '') ? (float)$input['salary'] : null, // Forza null se vuoto/non presente
            'notes' => $input['notes'] ?? null,
        ];

        try {
            $result = $this->db->insert('teacher_contracts', $dataToInsert);

             if ($result === false || $result === 0) { throw new \Exception("Failed to insert teacher contract."); }

            $newId = $this->db->lastInsertId();
            http_response_code(201);
            $this->show(['id' => $newId]); // Mostra il contratto appena creato

        } catch (UniqueConstraintViolationException $e) {
             http_response_code(409);
             error_log("Error creating teacher contract (duplicate teacher/year?): " . $e->getMessage());
             echo json_encode(['error' => 'Failed to create contract. A contract for this teacher and school year might already exist.']);
        } catch (ForeignKeyConstraintViolationException $e) {
             http_response_code(400);
             error_log("Error creating teacher contract (invalid teacher/year/structure ID?): " . $e->getMessage());
             echo json_encode(['error' => 'Invalid teacher, school year, or structure ID provided.']);
        } catch (\Throwable $e) {
            http_response_code(500);
            error_log("Error creating teacher contract: " . $e->getMessage());
            echo json_encode(['error' => 'Failed to create teacher contract']);
        }
    }

    /**
     * Aggiorna un contratto esistente.
     * PUT /api/teacher-contracts/{id}
     */
    public function update(array $vars): void
    {
        $id = $vars['id'] ?? null;
         if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing contract ID']); return; }

        // Leggi il corpo JSON della richiesta
        $input = json_decode(file_get_contents('php://input'), true);
         if (json_last_error() !== JSON_ERROR_NONE || !is_array($input)) {
             http_response_code(400);
             echo json_encode(['error' => 'Invalid JSON input']);
             return;
        }
         if (empty($input)) { http_response_code(400); echo json_encode(['error' => 'Missing update data']); return; }


        $dataToUpdate = [];
        $allowedFields = ['teacher_id', 'school_year_id', 'structure_id', 'contract_type', 'start_date', 'end_date', 'weekly_hours', 'salary', 'notes'];
        foreach ($allowedFields as $field) {
            if (array_key_exists($field, $input)) {
                $value = $input[$field];
                // Gestione specifica per i campi che possono essere NULL
                if (in_array($field, ['structure_id', 'end_date', 'weekly_hours', 'salary', 'notes'])) {
                    if ($value === '' || $value === null) {
                        $dataToUpdate[$field] = null;
                    } elseif ($field === 'structure_id') {
                         $dataToUpdate[$field] = (int)$value; // Cast a int se non null/vuoto
                    } elseif ($field === 'weekly_hours' || $field === 'salary') {
                         $dataToUpdate[$field] = (float)$value; // Cast a float se non null/vuoto
                    } else {
                         $dataToUpdate[$field] = $value; // Per end_date, contract_type, notes
                    }
                } else { // Campi obbligatori (teacher_id, school_year_id, start_date)
                    $dataToUpdate[$field] = $value;
                }
            }
        }

        if (empty($dataToUpdate)) { http_response_code(400); echo json_encode(['error' => 'No valid fields provided for update']); return; }

        try {
            $existing = $this->db->fetchOne('SELECT 1 FROM teacher_contracts WHERE id = ?', [$id]);
            if ($existing === false) { http_response_code(404); echo json_encode(['error' => "Contract with ID {$id} not found"]); return; }

            $this->db->update('teacher_contracts', $dataToUpdate, ['id' => $id]);

            $this->show(['id' => $id]); // Mostra il contratto aggiornato

        } catch (UniqueConstraintViolationException $e) {
             http_response_code(409);
             error_log("Error updating teacher contract {$id} (duplicate teacher/year?): " . $e->getMessage());
             echo json_encode(['error' => 'Failed to update contract. A contract for this teacher and school year might already exist.']);
        } catch (ForeignKeyConstraintViolationException $e) {
             http_response_code(400);
             error_log("Error updating teacher contract {$id} (invalid teacher/year/structure ID?): " . $e->getMessage());
             echo json_encode(['error' => 'Invalid teacher, school year, or structure ID provided.']);
        } catch (\Throwable $e) {
            http_response_code(500);
            error_log("Error updating teacher contract {$id}: " . $e->getMessage());
            echo json_encode(['error' => 'Failed to update teacher contract']);
        }
    }

    /**
     * Elimina un contratto.
     * DELETE /api/teacher-contracts/{id}
     */
    public function delete(array $vars): void
    {
        $id = $vars['id'] ?? null;
        if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing contract ID']); return; }

        try {
            $existing = $this->db->fetchOne('SELECT 1 FROM teacher_contracts WHERE id = ?', [$id]);
            if ($existing === false) { http_response_code(404); echo json_encode(['error' => "Contract with ID {$id} not found"]); return; }

            $deletedRows = $this->db->delete('teacher_contracts', ['id' => $id]);

            if ($deletedRows > 0) {
                http_response_code(204); // No Content
            } else {
                 http_response_code(500);
                 error_log("Failed to delete teacher contract {$id}, delete returned 0 rows affected.");
                 echo json_encode(['error' => 'Failed to delete teacher contract']);
            }

        } catch (\Throwable $e) {
            http_response_code(500);
            error_log("Error deleting teacher contract {$id}: " . $e->getMessage());
            echo json_encode(['error' => 'Failed to delete teacher contract']);
        }
    }
}