<?php

declare(strict_types=1);

namespace App\Modules\Interaction;

use App\Core\Database;

/**
 * InteractionService — Manages validation coordination, transactional database
 * upserts, and workspace isolation for guest interactions (RSVPs and wishes).
 *
 * @package Inveetaire
 * @ref     PILOT-005
 */
class InteractionService
{
    private InteractionModel $model;

    public function __construct()
    {
        $this->model = new InteractionModel();
    }

    /**
     * Process and upsert a guest's RSVP response.
     *
     * @param string $slug
     * @param string $token
     * @param array  $data
     * @return array Output array with success indicator and errors array if validation failed.
     */
    public function saveRsvp(string $slug, string $token, array $data): array
    {
        $ws = $this->model->getWorkspaceBySlug($slug);
        if ($ws === null) {
            throw new \InvalidArgumentException("Invalid wedding path slug.");
        }

        $wsId = (int) $ws['id'];
        $guest = $this->model->getGuestByToken($wsId, $token);
        if ($guest === null) {
            throw new \InvalidArgumentException("Invalid guest invitation code.");
        }

        $invitation = $this->model->getInvitationByWorkspace($wsId);
        if ($invitation === null || ($invitation['invitation_status'] ?? '') !== 'published') {
            return [
                'success' => false,
                'errors'  => ['invitation' => 'RSVP is not available as this invitation is not currently published.']
            ];
        }

        if (empty($invitation['rsvp_enabled'])) {
            return [
                'success' => false,
                'errors'  => ['invitation' => 'RSVP form is currently disabled for this invitation.']
            ];
        }

        $guestId = (int) $guest['id'];
        $invitedPax = (int) $guest['invited_pax'];
        $existingRsvp = $this->model->getGuestRsvp($guestId);

        // Validate with deadline, edit permission, pax limit, and guest notes checks
        $validator = new InteractionValidator();
        $errors = $validator->validateRsvp($data, $invitedPax, $invitation, $existingRsvp);
        if (!empty($errors)) {
            return [
                'success' => false,
                'errors'  => $errors
            ];
        }

        $response = trim((string) $data['response']);
        // Force pax to 0 if declined
        $confirmedPax = ($response === 'declined') ? 0 : (int) $data['confirmed_pax'];
        $message = isset($data['notes']) ? trim((string) $data['notes']) : (isset($data['message']) ? trim((string) $data['message']) : null);
        if ($message === '') {
            $message = null;
        }

        // Transaction block to guarantee database sync state
        $db = Database::getConnection();
        try {
            $db->beginTransaction();

            $this->model->upsertRsvp($wsId, $guestId, $response, $confirmedPax, $message);
            $this->model->updateGuestRsvpStatus($wsId, $guestId, $response);

            $db->commit();
            return ['success' => true];
        } catch (\Throwable $e) {
            $db->rollBack();
            throw $e;
        }
    }

    /**
     * Process and upsert a guest's congratulatory wish message.
     *
     * @param string $slug
     * @param string $token
     * @param array  $data
     * @return array Output array with success indicator and errors array if validation failed.
     */
    public function saveWish(string $slug, string $token, array $data): array
    {
        $ws = $this->model->getWorkspaceBySlug($slug);
        if ($ws === null) {
            throw new \InvalidArgumentException("Invalid wedding path slug.");
        }

        $wsId = (int) $ws['id'];
        $guest = $this->model->getGuestByToken($wsId, $token);
        if ($guest === null) {
            throw new \InvalidArgumentException("Invalid guest invitation code.");
        }

        $invitation = $this->model->getInvitationByWorkspace($wsId);
        if ($invitation === null || ($invitation['invitation_status'] ?? '') !== 'published') {
            return [
                'success' => false,
                'errors'  => ['invitation' => 'Guest Book is not available as this invitation is not currently published.']
            ];
        }

        // Fetch wishes section configuration from invitation_sections
        $db = Database::getConnection();
        $stmtWishes = $db->prepare('SELECT is_visible, section_config FROM invitation_sections WHERE invitation_id = :invitation_id AND section_slug = \'wishes\' LIMIT 1');
        $stmtWishes->execute(['invitation_id' => $invitation['id']]);
        $wishesSec = $stmtWishes->fetch(\PDO::FETCH_ASSOC);

        $wishesEnabled = (bool) ($invitation['wish_wall_enabled'] ?? ($wishesSec['is_visible'] ?? true));
        if (!$wishesEnabled) {
            return [
                'success' => false,
                'errors'  => ['invitation' => 'Guest Book is currently disabled for this invitation.']
            ];
        }

        $wishesConfig = [];
        if ($wishesSec && !empty($wishesSec['section_config'])) {
            $decoded = json_decode((string) $wishesSec['section_config'], true);
            if (is_array($decoded)) {
                $wishesConfig = $decoded;
            }
        }

        $maxCharLimit = max(50, min(5000, (int) ($wishesConfig['max_char_limit'] ?? 1000)));
        $requireModeration = (bool) ($wishesConfig['require_moderation'] ?? false);

        $guestId = (int) $guest['id'];

        // Validate wish with dynamic character limit
        $validator = new InteractionValidator();
        $errors = $validator->validateWish($data, $maxCharLimit);
        if (!empty($errors)) {
            return [
                'success' => false,
                'errors'  => $errors
            ];
        }

        // Automatic mapping of guest name (never request input from user)
        $senderName = $guest['full_name'];
        $message = trim((string) $data['message']);

        // Determine moderation status
        $status = $requireModeration ? 'pending' : 'approved';
        $isVisible = !$requireModeration;

        $this->model->upsertWish($wsId, $guestId, $senderName, $message, $status, $isVisible);
        return [
            'success'   => true,
            'moderated' => $requireModeration
        ];
    }
}
