<?php

declare(strict_types=1);

namespace App\Modules\Invitation;

use App\Core\Database;
use App\Core\Logger;

/**
 * EventSessionModel — Database operations for Event Sessions.
 *
 * Manages multiple sessions per wedding event (e.g. Holy Matrimony Session 1, Session 2).
 * Ensures workspace scoping and parameterized queries.
 *
 * @package Inveetaire
 */
class EventSessionModel
{
    /**
     * Get all sessions for a specific wedding event.
     *
     * @param int $workspaceId
     * @param int $weddingEventId
     * @return array<int, array<string, mixed>>
     */
    public function getSessionsByEventId(int $workspaceId, int $weddingEventId): array
    {
        $db = Database::getConnection();
        $stmt = $db->prepare('
            SELECT id, wedding_event_id, workspace_id, session_name, start_time, end_time, 
                   venue_name, venue_address, description, sort_order, is_default, created_at, updated_at
            FROM event_sessions
            WHERE workspace_id = :workspace_id
              AND wedding_event_id = :event_id
            ORDER BY sort_order ASC, start_time ASC
        ');
        $stmt->execute([
            'workspace_id' => $workspaceId,
            'event_id'     => $weddingEventId
        ]);
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }

    /**
     * Get all event sessions for a workspace grouped by wedding_event_id.
     *
     * @param int $workspaceId
     * @return array<int, array<int, array<string, mixed>>> [wedding_event_id => [session, ...]]
     */
    public function getSessionsGroupedByEvent(int $workspaceId): array
    {
        $db = Database::getConnection();
        $stmt = $db->prepare('
            SELECT id, wedding_event_id, workspace_id, session_name, start_time, end_time, 
                   venue_name, venue_address, description, sort_order, is_default, created_at, updated_at
            FROM event_sessions
            WHERE workspace_id = :workspace_id
            ORDER BY wedding_event_id ASC, sort_order ASC, start_time ASC
        ');
        $stmt->execute(['workspace_id' => $workspaceId]);
        $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);

        $grouped = [];
        foreach ($rows as $row) {
            $eventId = (int) $row['wedding_event_id'];
            if (!isset($grouped[$eventId])) {
                $grouped[$eventId] = [];
            }
            $grouped[$eventId][] = $row;
        }

        return $grouped;
    }

    /**
     * Get a single session by ID scoped to workspace.
     *
     * @param int $workspaceId
     * @param int $sessionId
     * @return array<string, mixed>|null
     */
    public function getSessionById(int $workspaceId, int $sessionId): ?array
    {
        $db = Database::getConnection();
        $stmt = $db->prepare('
            SELECT id, wedding_event_id, workspace_id, session_name, start_time, end_time, 
                   venue_name, venue_address, description, sort_order, is_default, created_at, updated_at
            FROM event_sessions
            WHERE workspace_id = :workspace_id
              AND id = :session_id
            LIMIT 1
        ');
        $stmt->execute([
            'workspace_id' => $workspaceId,
            'session_id'   => $sessionId
        ]);
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
        return $row !== false ? $row : null;
    }

    /**
     * Get the default session for a specific wedding event.
     *
     * @param int $workspaceId
     * @param int $weddingEventId
     * @return array<string, mixed>|null
     */
    public function getDefaultSession(int $workspaceId, int $weddingEventId): ?array
    {
        $sessions = $this->getSessionsByEventId($workspaceId, $weddingEventId);
        if (empty($sessions)) {
            return null;
        }

        foreach ($sessions as $session) {
            if ((int) ($session['is_default'] ?? 0) === 1) {
                return $session;
            }
        }

        // Fallback to first session if none marked default
        return $sessions[0];
    }

    /**
     * Insert a new session for a wedding event.
     *
     * @param int   $workspaceId
     * @param array $data
     * @return int Inserted Session ID
     */
    public function insertSession(int $workspaceId, array $data): int
    {
        $db = Database::getConnection();
        $stmt = $db->prepare('
            INSERT INTO event_sessions (
                wedding_event_id, workspace_id, session_name, start_time, end_time,
                venue_name, venue_address, description, sort_order, is_default
            ) VALUES (
                :wedding_event_id, :workspace_id, :session_name, :start_time, :end_time,
                :venue_name, :venue_address, :description, :sort_order, :is_default
            )
        ');

        $stmt->execute([
            'wedding_event_id' => (int) $data['wedding_event_id'],
            'workspace_id'     => $workspaceId,
            'session_name'     => (string) ($data['session_name'] ?? 'Session 1'),
            'start_time'       => (string) $data['start_time'],
            'end_time'         => !empty($data['end_time']) ? (string) $data['end_time'] : null,
            'venue_name'       => !empty($data['venue_name']) ? (string) $data['venue_name'] : null,
            'venue_address'    => !empty($data['venue_address']) ? (string) $data['venue_address'] : null,
            'description'      => !empty($data['description']) ? (string) $data['description'] : null,
            'sort_order'       => (int) ($data['sort_order'] ?? 1),
            'is_default'       => (int) ($data['is_default'] ?? 0),
        ]);

        return (int) $db->lastInsertId();
    }

    /**
     * Update an existing session.
     *
     * @param int   $workspaceId
     * @param int   $sessionId
     * @param array $data
     * @return bool
     */
    public function updateSession(int $workspaceId, int $sessionId, array $data): bool
    {
        $db = Database::getConnection();
        $stmt = $db->prepare('
            UPDATE event_sessions
            SET session_name = :session_name,
                start_time   = :start_time,
                end_time     = :end_time,
                venue_name   = :venue_name,
                venue_address = :venue_address,
                description  = :description,
                sort_order   = :sort_order,
                is_default   = :is_default,
                updated_at   = CURRENT_TIMESTAMP
            WHERE id = :session_id
              AND workspace_id = :workspace_id
        ');

        return $stmt->execute([
            'session_id'    => $sessionId,
            'workspace_id'  => $workspaceId,
            'session_name'  => (string) ($data['session_name'] ?? 'Session 1'),
            'start_time'    => (string) $data['start_time'],
            'end_time'      => !empty($data['end_time']) ? (string) $data['end_time'] : null,
            'venue_name'    => !empty($data['venue_name']) ? (string) $data['venue_name'] : null,
            'venue_address' => !empty($data['venue_address']) ? (string) $data['venue_address'] : null,
            'description'   => !empty($data['description']) ? (string) $data['description'] : null,
            'sort_order'    => (int) ($data['sort_order'] ?? 1),
            'is_default'    => (int) ($data['is_default'] ?? 0),
        ]);
    }

    /**
     * Delete a session. Cannot delete if it is the only session for that event.
     *
     * @param int $workspaceId
     * @param int $sessionId
     * @return bool
     */
    public function deleteSession(int $workspaceId, int $sessionId): bool
    {
        $session = $this->getSessionById($workspaceId, $sessionId);
        if ($session === null) {
            return false;
        }

        $allSessions = $this->getSessionsByEventId($workspaceId, (int) $session['wedding_event_id']);
        if (count($allSessions) <= 1) {
            Logger::warning('EventSessionModel: blocked deletion of sole remaining event session', [
                'workspace_id' => $workspaceId,
                'session_id'   => $sessionId
            ]);
            return false; // Every event must have at least ONE session
        }

        $db = Database::getConnection();
        $stmt = $db->prepare('DELETE FROM event_sessions WHERE id = :session_id AND workspace_id = :workspace_id');
        return $stmt->execute(['session_id' => $sessionId, 'workspace_id' => $workspaceId]);
    }

    /**
     * Ensure that every active wedding event in the workspace has at least one Default Session.
     * Inherits date, venue_name, and venue_address from wedding_events.
     *
     * @param int $workspaceId
     * @return void
     */
    public function ensureDefaultSessions(int $workspaceId): void
    {
        $db = Database::getConnection();

        // 1. Fetch all active wedding events for workspace
        $stmtEvents = $db->prepare('
            SELECT id, event_name, event_date, venue_name, venue_address 
            FROM wedding_events 
            WHERE workspace_id = :workspace_id 
              AND is_deleted = 0
        ');
        $stmtEvents->execute(['workspace_id' => $workspaceId]);
        $events = $stmtEvents->fetchAll(\PDO::FETCH_ASSOC);

        if (empty($events)) {
            return;
        }

        // 2. For each wedding event, check if any sessions exist
        foreach ($events as $event) {
            $eventId = (int) $event['id'];
            $stmtCheck = $db->prepare('
                SELECT id 
                FROM event_sessions 
                WHERE workspace_id = :workspace_id 
                  AND wedding_event_id = :event_id 
                LIMIT 1
            ');
            $stmtCheck->execute([
                'workspace_id' => $workspaceId,
                'event_id'     => $eventId
            ]);

            if ($stmtCheck->fetch() === false) {
                // No session exists for this wedding event — create Default Session
                $stmtInsert = $db->prepare('
                    INSERT INTO event_sessions (
                        wedding_event_id, workspace_id, session_name, start_time, 
                        venue_name, venue_address, sort_order, is_default
                    ) VALUES (
                        :event_id, :workspace_id, :name, :start_time, 
                        :venue_name, :venue_address, 1, 1
                    )
                ');
                $stmtInsert->execute([
                    'event_id'      => $eventId,
                    'workspace_id'  => $workspaceId,
                    'name'          => 'Default Session',
                    'start_time'    => $event['event_date'],
                    'venue_name'    => $event['venue_name'],
                    'venue_address' => $event['venue_address'],
                ]);
            }
        }
    }
}
