<?php

declare(strict_types=1);

namespace App\Controllers;

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

class ShiftDefinitionController
{
    private Connection $db;

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

    /**
     * Mostra un elenco di definizioni di turno.
     * GET /api/shift-definitions
     */
    public function index(): void
    {
        try {
            $queryBuilder = $this->db->createQueryBuilder();
            $shifts = $queryBuilder
                ->select('*')
                ->from('shift_definitions')
                ->orderBy('start_time', 'ASC') // Ordina per orario inizio
                ->fetchAllAssociative();

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

    /**
     * Mostra una definizione di turno specifica.
     * GET /api/shift-definitions/{id}
     */
    public function show(array $vars): void
    {
        $id = $vars['id'] ?? null;
        if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing shift definition ID']); return; }

        try {
            $shift = $this->db->fetchAssociative('SELECT * FROM shift_definitions WHERE id = ?', [$id]);

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

    /**
     * Crea una nuova definizione di turno.
     * POST /api/shift-definitions
     */
    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['name']) || empty($input['start_time']) || empty($input['end_time'])) {
            http_response_code(400);
            echo json_encode(['error' => 'Missing required fields: name, start_time, end_time']);
            return;
        }
        // Validazione formato orario (HH:MM o HH:MM:SS)
        $timeRegex = '/^([01]\d|2[0-3]):([0-5]\d)(:([0-5]\d))?$/';
        if (!preg_match($timeRegex, $input['start_time']) || !preg_match($timeRegex, $input['end_time'])) {
             http_response_code(400);
             echo json_encode(['error' => 'Invalid time format. Use HH:MM or HH:MM:SS.']);
             return;
        }
         // Validazione logica orari (opzionale, ma utile)
         if (strtotime($input['end_time']) <= strtotime($input['start_time'])) {
              http_response_code(400);
              echo json_encode(['error' => 'End time must be after start time.']);
              return;
         }


        $dataToInsert = [
            'name' => $input['name'],
            'start_time' => $input['start_time'],
            'end_time' => $input['end_time'],
            'notes' => $input['notes'] ?? null,
        ];

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

            $newId = $this->db->lastInsertId();
            http_response_code(201);
            $this->show(['id' => $newId]);

        } catch (UniqueConstraintViolationException $e) {
             http_response_code(409);
             error_log("Error creating shift definition (duplicate name?): " . $e->getMessage());
             echo json_encode(['error' => 'Failed to create shift definition. Name might already exist.']);
        } catch (\Throwable $e) {
            http_response_code(500);
            error_log("Error creating shift definition: " . $e->getMessage());
            echo json_encode(['error' => 'Failed to create shift definition']);
        }
    }

    /**
     * Aggiorna una definizione di turno esistente.
     * PUT /api/shift-definitions/{id}
     */
    public function update(array $vars): void
    {
        $id = $vars['id'] ?? null;
        if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing shift definition 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; }

         // Validazione formato orario se presenti
         $timeRegex = '/^([01]\d|2[0-3]):([0-5]\d)(:([0-5]\d))?$/';
         if (isset($input['start_time']) && !preg_match($timeRegex, $input['start_time'])) {
              http_response_code(400); echo json_encode(['error' => 'Invalid start_time format.']); return;
         }
          if (isset($input['end_time']) && !preg_match($timeRegex, $input['end_time'])) {
              http_response_code(400); echo json_encode(['error' => 'Invalid end_time format.']); return;
         }
          // Validazione logica orari se entrambi presenti
          $startTime = $input['start_time'] ?? null;
          $endTime = $input['end_time'] ?? null;
          if ($startTime && $endTime && strtotime($endTime) <= strtotime($startTime)) {
               http_response_code(400); echo json_encode(['error' => 'End time must be after start time.']); return;
          }
          // Validazione con orari esistenti se solo uno viene fornito (più complessa, omessa per brevità)


        $dataToUpdate = [];
        $allowedFields = ['name', 'start_time', 'end_time', 'notes'];
        foreach ($allowedFields as $field) {
            if (array_key_exists($field, $input)) {
                 $dataToUpdate[$field] = ($input[$field] === '') ? null : $input[$field];
            }
        }

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

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

        } catch (UniqueConstraintViolationException $e) {
             http_response_code(409);
             error_log("Error updating shift definition {$id} (duplicate name?): " . $e->getMessage());
             echo json_encode(['error' => 'Failed to update shift definition. Name might already exist.']);
        } catch (\Throwable $e) {
            http_response_code(500);
            error_log("Error updating shift definition {$id}: " . $e->getMessage());
            echo json_encode(['error' => 'Failed to update shift definition']);
        }
    }

    /**
     * Elimina una definizione di turno.
     * DELETE /api/shift-definitions/{id}
     */
    public function delete(array $vars): void
    {
        $id = $vars['id'] ?? null;
        if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing shift definition ID']); return; }

        try {
             // Aggiungere qui controlli se la definizione è usata in turni effettivi?

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

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

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

        } catch (\Throwable $e) {
            // Gestire ForeignKeyConstraintViolationException se la definizione è usata altrove
            http_response_code(500);
            error_log("Error deleting shift definition {$id}: " . $e->getMessage());
            echo json_encode(['error' => 'Failed to delete shift definition. It might be in use.']);
        }
    }
}