<?php

namespace Mtc\Plugins\WeightVerification\Src;

use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Mtc\Plugins\MembersMessaging\Classes\Message;
use Mtc\Plugins\MembersMessaging\Classes\Thread;
use Mtc\Plugins\WeightVerification\Src\Models\WeightVerification;
use Mtc\Shop\Order;

class WeightVerificationService
{
    /**
     * Create a pending verification when a paid order contains a flagged item.
     *
     * Idempotent: an order only ever gets a single verification record.
     */
    public function handleOrderPaid(int $orderId): ?WeightVerification
    {
        if (!config('weight_verification.enabled')) {
            return null;
        }

        $order = Order::query()
            ->with('items.item')
            ->find($orderId);

        if (empty($order)) {
            return null;
        }

        $requiresVerification = $order->items->contains(function ($orderItem) {
            return !empty($orderItem->item) && (bool) $orderItem->item->requires_weight_verification;
        });

        if (!$requiresVerification) {
            return null;
        }

        return WeightVerification::query()
            ->firstOrCreate(
                ['order_id' => $order->id],
                [
                    'member_id' => (int) $order->member,
                    'status' => WeightVerification::STATUS_PENDING,
                ]
            );
    }

    /**
     * The most recent verification for a member, or null.
     */
    public function latestForMember(int $memberId): ?WeightVerification
    {
        return WeightVerification::query()
            ->forMember($memberId)
            ->first();
    }

    /**
     * Every verification the member still needs to act on, oldest first so the
     * patient clears each flagged order in the order they were placed.
     *
     * A member can have more than one flagged order open at once, so the
     * dashboard must surface all of them rather than only the newest.
     */
    public function actionRequiredForMember(int $memberId): \Illuminate\Support\Collection
    {
        return WeightVerification::query()
            ->where('member_id', $memberId)
            ->whereIn('status', WeightVerification::ACTION_REQUIRED_STATUSES)
            ->orderBy('id')
            ->get();
    }

    /**
     * Lightweight summary for the members menu indicator.
     *
     * Returns null when the member has no verifications at all, otherwise
     * whether any verification currently needs the patient to act. Uses a
     * single status-only query rather than hydrating full models.
     */
    public function menuSummaryForMember(int $memberId): ?array
    {
        $statuses = WeightVerification::query()
            ->where('member_id', $memberId)
            ->pluck('status');

        if ($statuses->isEmpty()) {
            return null;
        }

        return [
            'action_required' => $statuses
                ->intersect(WeightVerification::ACTION_REQUIRED_STATUSES)
                ->isNotEmpty(),
        ];
    }

    /**
     * A single verification owned by the given member, or null.
     *
     * Used to target the specific verification a patient is submitting photos
     * for, rather than trusting "latest" (which stranded older orders).
     */
    public function forMemberAndId(int $memberId, int $verificationId): ?WeightVerification
    {
        return WeightVerification::query()
            ->where('member_id', $memberId)
            ->where('id', $verificationId)
            ->first();
    }

    /**
     * Verification attached to an order, or null.
     */
    public function forOrder(int $orderId): ?WeightVerification
    {
        return WeightVerification::query()
            ->where('order_id', $orderId)
            ->orderByDesc('id')
            ->first();
    }

    /**
     * Whether the given order is blocked from approval because its
     * weight verification photos have not been submitted yet.
     */
    public function approvalBlockedForOrder(int $orderId): bool
    {
        $verification = $this->forOrder($orderId);

        if (empty($verification)) {
            return false;
        }

        return !$verification->isSubmitted();
    }

    /**
     * Prescriber requests new photos: re-open the patient tab and notify them
     * through the existing messaging system (message + email).
     */
    public function requestResubmission(WeightVerification $verification, $admin, string $message): WeightVerification
    {
        $verification->update([
            'status' => WeightVerification::STATUS_RESUBMIT_REQUIRED,
            'reviewed_at' => Carbon::now(),
            'reviewed_by' => $admin->id ?? null,
            'decline_reason' => $message,
        ]);

        // Re-opening the tab must succeed even if the notification fails — the
        // patient still sees the action-required state on their dashboard.
        try {
            $this->notifyPatient($verification, $admin, $message);
        } catch (\Throwable $e) {
            Log::warning('Weight verification resubmission notification failed: ' . $e->getMessage());
        }

        return $verification;
    }

    /**
     * Message the patient through the existing messaging system + email.
     *
     * Sent against the verification's known member rather than re-deriving the
     * patient from the order email, which is unreliable when emails are encrypted.
     */
    protected function notifyPatient(WeightVerification $verification, $admin, string $message): void
    {
        $member = $verification->member;
        if (empty($member) || empty($member->id)) {
            return;
        }

        $thread = Thread::query()->create([
            'url' => str_replace('.', '-', uniqid('cp_', true)),
            'order_id' => $verification->order_id,
            'assigned' => 1,
            'category' => 1, // Doctor query
        ]);

        Message::query()->create([
            'thread_id' => $thread->id,
            'member_id' => $admin->id ?? null,
            'text' => $message,
            'private' => 0,
            'admin' => true,
        ]);

        $thread->addParticipant($member);
        if (!empty($admin)) {
            $thread->addParticipant($admin, 1);
        }

        $emailBody = template('emails/new_message.twig', [
            'member' => $member,
            'message_text' => $message,
            'thread_url' => SITE_URL . '/members/messages/view_thread.php?thread=' . $thread->url,
        ]);
        email(
            $member->email,
            "You've received a new message on " . config('app.name'),
            $emailBody,
            ['dev_copy' => defined('DEV_MODE') ? DEV_MODE : false]
        );
    }

    /**
     * Mark the verification approved (called when the prescriber approves the item).
     */
    public function markApproved(WeightVerification $verification, $admin = null): WeightVerification
    {
        $verification->update([
            'status' => WeightVerification::STATUS_APPROVED,
            'reviewed_at' => Carbon::now(),
            'reviewed_by' => $admin->id ?? null,
        ]);

        return $verification;
    }
}
