<?php

declare(strict_types=1);

namespace App\Controllers;

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

class ChildController
{
    private Connection $db;

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

    /**
     * Mostra un elenco di bambini.
     * GET /api/children
     * Accetta query params: structure_id, is_active
     */
    public function index(): void
    {
        try {
            $queryBuilder = $this->db->createQueryBuilder()
                ->select(
                    'c.id', 'c.first_name', 'c.last_name', 'c.date_of_birth',
                    'c.enrollment_date', 'c.structure_id', 'c.is_active',
                    's.name AS structure_name' // Nome struttura associata
                )
                ->from('children', 'c')
                ->leftJoin('c', 'structures', 's', 'c.structure_id = s.id')
                ->orderBy('c.last_name', 'ASC')
                ->addOrderBy('c.first_name', 'ASC');

            // Filtri opzionali
            if (isset($_GET['structure_id']) && $_GET['structure_id'] !== '') {
                $queryBuilder->andWhere('c.structure_id = :structureId')
                             ->setParameter('structureId', $_GET['structure_id']);
            }
             if (isset($_GET['is_active'])) {
                 // Converte il valore stringa 'true'/'false' o 1/0 in booleano
                $isActive = filter_var($_GET['is_active'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
                 if ($isActive !== null) {
                    $queryBuilder->andWhere('c.is_active = :isActive')
                                 ->setParameter('isActive', $isActive, \Doctrine\DBAL\ParameterType::BOOLEAN);
                 }
            }

            $children = $queryBuilder->fetchAllAssociative();
            echo json_encode($children);

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

    /**
     * Mostra un bambino specifico.
     * GET /api/children/{id}
     */
    public function show(array $vars): void
    {
        $id = $vars['id'] ?? null;
        if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing child ID']); return; }

        try {
             $queryBuilder = $this->db->createQueryBuilder()
                ->select('c.*', 's.name AS structure_name')
                ->from('children', 'c')
                ->leftJoin('c', 'structures', 's', 'c.structure_id = s.id')
                ->where('c.id = :id')
                ->setParameter('id', $id);

            $child = $queryBuilder->fetchAssociative();

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

    /**
     * Crea un nuovo bambino.
     * POST /api/children
     */
    public function store(): void
    {
        $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;
        }

        // Validazione campi obbligatori
        if (empty($input['first_name']) || empty($input['last_name']) || empty($input['date_of_birth']) || empty($input['enrollment_date'])) {
            http_response_code(400);
            echo json_encode(['error' => 'Missing required fields: first_name, last_name, date_of_birth, enrollment_date']);
            return;
        }

        $dataToInsert = [
            'first_name' => $input['first_name'],
            'last_name' => $input['last_name'],
            'date_of_birth' => $input['date_of_birth'], // Assumiamo YYYY-MM-DD
            'enrollment_date' => $input['enrollment_date'], // Assumiamo YYYY-MM-DD
            'structure_id' => (isset($input['structure_id']) && $input['structure_id'] !== '') ? (int)$input['structure_id'] : null,
            'parent1_name' => $input['parent1_name'] ?? null,
            'parent1_phone' => $input['parent1_phone'] ?? null,
            'parent1_email' => $input['parent1_email'] ?? null,
            'parent2_name' => $input['parent2_name'] ?? null,
            'parent2_phone' => $input['parent2_phone'] ?? null,
            'parent2_email' => $input['parent2_email'] ?? null,
            'address' => $input['address'] ?? null,
            'city' => $input['city'] ?? null,
            'notes' => $input['notes'] ?? null,
            'is_active' => isset($input['is_active']) ? (bool)$input['is_active'] : true, // Default a true
        ];

        try {
            $result = $this->db->insert('children', $dataToInsert);
            if ($result === false || $result === 0) { throw new \Exception("Failed to insert child."); }

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

        } catch (ForeignKeyConstraintViolationException $e) {
             http_response_code(400);
             error_log("Error creating child (invalid structure ID?): " . $e->getMessage());
             echo json_encode(['error' => 'Invalid structure ID provided.']);
        } catch (\Throwable $e) {
            http_response_code(500);
            error_log("Error creating child: " . $e->getMessage());
            echo json_encode(['error' => 'Failed to create child']);
        }
    }

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

        $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 = [
            'first_name', 'last_name', 'date_of_birth', 'enrollment_date', 'structure_id',
            'parent1_name', 'parent1_phone', 'parent1_email',
            'parent2_name', 'parent2_phone', 'parent2_email',
            'address', 'city', 'notes', 'is_active'
        ];

        foreach ($allowedFields as $field) {
            if (array_key_exists($field, $input)) {
                $value = $input[$field];
                if ($field === 'is_active') {
                    $dataToUpdate[$field] = (bool)$value;
                } elseif ($field === 'structure_id' && ($value === '' || $value === null)) {
                    $dataToUpdate[$field] = null;
                } elseif ($field === 'structure_id') {
                     $dataToUpdate[$field] = (int)$value;
                } else {
                    $dataToUpdate[$field] = ($value === '') ? null : $value; // Imposta null se stringa vuota per altri campi opzionali
                }
            }
        }

        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 children WHERE id = ?', [$id]);
            if ($existing === false) { http_response_code(404); echo json_encode(['error' => "Child with ID {$id} not found"]); return; }

            $this->db->update('children', $dataToUpdate, ['id' => $id]);
            $this->show(['id' => $id]); // Mostra il bambino aggiornato

        } catch (ForeignKeyConstraintViolationException $e) {
             http_response_code(400);
             error_log("Error updating child {$id} (invalid structure ID?): " . $e->getMessage());
             echo json_encode(['error' => 'Invalid structure ID provided.']);
        } catch (\Throwable $e) {
            http_response_code(500);
            error_log("Error updating child {$id}: " . $e->getMessage());
            echo json_encode(['error' => 'Failed to update child']);
        }
    }

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

        try {
             // Aggiungere qui controlli se il bambino è referenziato altrove (es. presenze, pagamenti)
             // prima di permettere l'eliminazione.

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

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

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

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