<?php

declare(strict_types=1);

namespace App\Modules\Invitation;

/**
 * InvitationValidator — Form Input Validator for Wedding Invitation configuration.
 *
 * Validates inputs for groom/bride names, wedding date, wedding time, venue details,
 * story, cover image, hero quote, theme, and publication status.
 *
 * @package Inveetaire
 * @ref     PILOT-001
 */
class InvitationValidator
{
    /**
     * Validate invitation inputs.
     *
     * @param array $data Input parameters (typically from $_POST).
     * @return array<string, string> Keyed error messages; empty if valid.
     */
    public function validate(array $data, int $workspaceId = 0): array
    {
        $errors = [];

        // 1. Groom Display Name
        $groomName = isset($data['groom_display_name']) ? trim((string) $data['groom_display_name']) : '';
        if ($groomName === '') {
            $errors['groom_display_name'] = 'Groom display name is required.';
        } elseif (mb_strlen($groomName) > 100) {
            $errors['groom_display_name'] = 'Groom display name must not exceed 100 characters.';
        }

        // 2. Bride Display Name
        $brideName = isset($data['bride_display_name']) ? trim((string) $data['bride_display_name']) : '';
        if ($brideName === '') {
            $errors['bride_display_name'] = 'Bride display name is required.';
        } elseif (mb_strlen($brideName) > 100) {
            $errors['bride_display_name'] = 'Bride display name must not exceed 100 characters.';
        }

        // 3. Optional Legacy Fields Fallback
        $weddingDate = isset($data['wedding_date']) ? trim((string) $data['wedding_date']) : '';
        if ($weddingDate !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $weddingDate)) {
            $errors['wedding_date'] = 'Wedding date must be in YYYY-MM-DD format.';
        }

        // 8. Love Story
        $loveStory = isset($data['love_story']) ? trim((string) $data['love_story']) : '';
        if ($loveStory !== '') {
            if (mb_strlen($loveStory) > 65535) {
                $errors['love_story'] = 'Love story text must not exceed 65,535 characters.';
            }
        }

        // 9. Cover Image URL
        $coverImage = isset($data['cover_image']) ? trim((string) $data['cover_image']) : '';
        if ($coverImage !== '') {
            if (mb_strlen($coverImage) > 500) {
                $errors['cover_image'] = 'Cover image URL must not exceed 500 characters.';
            } elseif (!filter_var($coverImage, FILTER_VALIDATE_URL)) {
                $errors['cover_image'] = 'Please enter a valid cover image URL.';
            }
        }

        // 10. Hero Quote
        $heroQuote = isset($data['hero_quote']) ? trim((string) $data['hero_quote']) : '';
        if ($heroQuote !== '') {
            if (mb_strlen($heroQuote) > 500) {
                $errors['hero_quote'] = 'Hero quote must not exceed 500 characters.';
            }
        }

        // 11. Theme Version ID
        $themeVerId = isset($data['theme_version_id']) ? (string) $data['theme_version_id'] : '';
        if ($themeVerId === '') {
            $errors['theme_version_id'] = 'Theme selection is required.';
        } else {
            $themeVerVal = filter_var($themeVerId, FILTER_VALIDATE_INT);
            if ($themeVerVal === false) {
                $errors['theme_version_id'] = 'Please select a valid theme version.';
            }
        }

        // 12. Publication Status
        $status = isset($data['invitation_status']) ? trim((string) $data['invitation_status']) : '';
        if ($status === '') {
            $errors['invitation_status'] = 'Publication status is required.';
        } elseif (!in_array($status, ['draft', 'published'], true)) {
            $errors['invitation_status'] = 'Invalid publication status.';
        }

        // 13. Events & Invitation Times Validation
        if (isset($data['events']) && is_array($data['events'])) {
            foreach ($data['events'] as $idx => $evt) {
                $evtId = (int) ($evt['id'] ?? 0);
                $eName = trim((string) ($evt['event_name'] ?? ('Ceremony ' . ($idx + 1))));
                $rawTimes = $evt['invitation_times'] ?? [];
                if (is_string($rawTimes)) {
                    $rawTimes = [$rawTimes];
                }

                $validTimes = [];
                foreach ($rawTimes as $t) {
                    $tTrim = trim((string) $t);
                    if ($tTrim !== '') {
                        if (!preg_match('/^(?:[01]\d|2[0-3]):[0-5]\d$/', $tTrim)) {
                            $errors["event_{$idx}_time"] = "Event '{$eName}' contains an invalid time format '{$tTrim}'. Expected HH:mm.";
                        } else {
                            $validTimes[] = $tTrim;
                        }
                    }
                }

                if (empty($validTimes)) {
                    $errors["event_{$idx}_times"] = "Event '{$eName}' must have at least one invitation time.";
                } elseif (count(array_unique($validTimes)) < count($validTimes)) {
                    $errors["event_{$idx}_times"] = "Event '{$eName}' contains duplicate invitation times.";
                } elseif ($evtId > 0) {
                    // Check if any invitation time being removed has active guest assignments
                    $db = \App\Core\Database::getConnection();
                    $stmtExisting = $db->prepare('
                        SELECT id, start_time 
                        FROM event_sessions 
                        WHERE workspace_id = :workspace_id AND wedding_event_id = :event_id 
                        ORDER BY sort_order ASC, id ASC
                    ');
                    $wsId = $workspaceId > 0 ? $workspaceId : (int) (\App\Core\Session::get('active_workspace_id') ?: 0);
                    if ($wsId > 0) {
                        $stmtExisting->execute(['workspace_id' => $wsId, 'event_id' => $evtId]);
                        $existingSessions = $stmtExisting->fetchAll(\PDO::FETCH_ASSOC);

                        $submittedCount = count(array_unique($validTimes));
                        if (count($existingSessions) > $submittedCount) {
                            for ($i = $submittedCount; $i < count($existingSessions); $i++) {
                                $sessId = (int) $existingSessions[$i]['id'];
                                $stmtCount = $db->prepare('SELECT COUNT(*) FROM guest_events WHERE event_session_id = :session_id');
                                $stmtCount->execute(['session_id' => $sessId]);
                                $assignedCount = (int) $stmtCount->fetchColumn();

                                if ($assignedCount > 0) {
                                    $timeStr = !empty($existingSessions[$i]['start_time']) 
                                        ? (new \DateTime($existingSessions[$i]['start_time']))->format('H:i') 
                                        : 'Slot ' . ($i + 1);
                                    $errors["event_{$idx}_times"] = "Invitation Time '{$timeStr}' for {$eName} is currently assigned to {$assignedCount} guest(s). Please reassign these guests in Guest Management before removing this time slot.";
                                    break;
                                }
                            }
                        }
                    }
                }

                // 14. Google Maps UX Validation (maps_url vs maps_embed_url)
                // Case A: User pastes a Share URL (e.g. maps.app.goo.gl) into Embed URL field
                $embedCode = trim((string) ($evt['maps_embed_code'] ?? ''));
                if ($embedCode !== '') {
                    $isIframe = (strpos($embedCode, '<iframe') !== false);
                    $isEmbedUrl = (preg_match('/^https:\/\/(?:www\.)?google\.com\/maps\/embed/i', $embedCode) === 1);
                    if (!$isIframe && !$isEmbedUrl) {
                        $errors["event_{$idx}_maps_embed_code"] = "Invalid Google Maps Embed URL for {$eName}. Please paste a Google Maps Embed URL (beginning with https://www.google.com/maps/embed) or paste the full <iframe> code.";
                    }
                }

                // Case B: User pastes an Embed URL (e.g. google.com/maps/embed or <iframe) into Open URL field
                $mapsUrl = trim((string) ($evt['maps_url'] ?? ''));
                if ($mapsUrl !== '') {
                    if (strpos($mapsUrl, '/maps/embed') !== false || strpos($mapsUrl, '<iframe') !== false) {
                        $errors["event_{$idx}_maps_url"] = "You pasted a Google Maps Embed URL into 'Open in Google Maps URL' for {$eName}. This field should contain a Google Maps Share URL (e.g. https://maps.app.goo.gl/...).";
                    }
                }
            }
        }

        return $errors;
    }
}
