<?php

declare(strict_types=1);

namespace App\Services\Entitlements;

use App\Models\Workspace;
use App\Models\WorkspaceSubscription;
use App\Services\Settings\SettingsResolver;
use Carbon\CarbonInterface;

final class WorkspaceSubscriptionResolver
{
    public const SOURCE_WORKSPACE_SUBSCRIPTION = 'workspace_subscription';

    /**
     * @return array<string, string>
     */
    public static function stateLabels(): array
    {
        return [
            WorkspaceSubscription::STATE_TRIAL => 'Trial',
            WorkspaceSubscription::STATE_ACTIVE => 'Active',
            WorkspaceSubscription::STATE_PAST_DUE => 'Past due',
            WorkspaceSubscription::STATE_CANCEL_AT_PERIOD_END => 'Cancellation pending',
            WorkspaceSubscription::STATE_ENDED => 'Ended',
        ];
    }

    public function __construct(
        private readonly SettingsResolver $settingsResolver,
    ) {}

    /**
     * @return array{
     *     workspace_id: int,
     *     subscription_present: bool,
     *     state: string|null,
     *     label: string|null,
     *     billing_reference: string|null,
     *     status_reason: string|null,
     *     key_date_label: string|null,
     *     key_date: CarbonInterface|null,
     *     needs_review: bool,
     *     source: string,
     *     fallback_status: bool,
     *     derived_lifecycle_state: string
     * }
     */
    public function summary(Workspace $workspace): array
    {
        $workspace->loadMissing('subscription');

        $subscription = $workspace->subscription;

        if ($subscription instanceof WorkspaceSubscription) {
            return $this->subscriptionSummary($workspace, $subscription);
        }

        return $this->fallbackSummary($workspace);
    }

    /**
     * @return array{
     *     workspace_id: int,
     *     subscription_present: bool,
     *     state: string,
     *     label: string,
     *     billing_reference: string|null,
     *     status_reason: string,
     *     key_date_label: string|null,
     *     key_date: CarbonInterface|null,
     *     needs_review: bool,
     *     source: string,
     *     fallback_status: bool,
     *     derived_lifecycle_state: string
     * }
     */
    private function subscriptionSummary(Workspace $workspace, WorkspaceSubscription $subscription): array
    {
        $state = in_array($subscription->state, WorkspaceSubscription::stateIds(), true)
            ? $subscription->state
            : WorkspaceSubscription::STATE_ACTIVE;

        $keyDate = $this->keyDateForSubscription($subscription, $state);

        return [
            'workspace_id' => (int) $workspace->getKey(),
            'subscription_present' => true,
            'state' => $state,
            'label' => self::stateLabels()[$state],
            'billing_reference' => $subscription->billing_reference,
            'status_reason' => $subscription->status_reason,
            'key_date_label' => $this->keyDateLabel($state),
            'key_date' => $keyDate,
            'needs_review' => $this->needsReview($state, $keyDate),
            'source' => self::SOURCE_WORKSPACE_SUBSCRIPTION,
            'fallback_status' => false,
            'derived_lifecycle_state' => $this->derivedLifecycleState($state),
        ];
    }

    /**
     * @return array{
     *     workspace_id: int,
     *     subscription_present: bool,
     *     state: null,
     *     label: null,
     *     billing_reference: null,
     *     status_reason: string|null,
     *     key_date_label: null,
     *     key_date: null,
     *     needs_review: bool,
     *     source: string,
     *     fallback_status: bool,
     *     derived_lifecycle_state: string
     * }
     */
    private function fallbackSummary(Workspace $workspace): array
    {
        $stateSetting = $this->settingsResolver->resolveDetailed(
            workspace: $workspace,
            domain: WorkspaceCommercialLifecycleResolver::SETTING_DOMAIN,
            key: WorkspaceCommercialLifecycleResolver::SETTING_COMMERCIAL_LIFECYCLE_STATE,
        );

        $rawState = is_string($stateSetting['value'] ?? null)
            ? strtolower(trim((string) $stateSetting['value']))
            : null;

        $derivedLifecycleState = in_array($rawState, WorkspaceCommercialLifecycleResolver::stateIds(), true)
            ? $rawState
            : WorkspaceCommercialLifecycleResolver::STATE_ACTIVE_PAID;

        $source = ($stateSetting['source'] ?? null) === 'workspace_override' && $rawState !== null
            ? WorkspaceCommercialLifecycleResolver::SOURCE_WORKSPACE_SETTING
            : WorkspaceCommercialLifecycleResolver::SOURCE_DEFAULT_ACTIVE_PAID;

        $statusReason = $this->settingsResolver->resolveValue(
            workspace: $workspace,
            domain: WorkspaceCommercialLifecycleResolver::SETTING_DOMAIN,
            key: WorkspaceCommercialLifecycleResolver::SETTING_COMMERCIAL_LIFECYCLE_REASON,
        );

        return [
            'workspace_id' => (int) $workspace->getKey(),
            'subscription_present' => false,
            'state' => null,
            'label' => null,
            'billing_reference' => null,
            'status_reason' => is_string($statusReason) && trim($statusReason) !== '' ? trim($statusReason) : null,
            'key_date_label' => null,
            'key_date' => null,
            'needs_review' => false,
            'source' => $source,
            'fallback_status' => true,
            'derived_lifecycle_state' => $derivedLifecycleState,
        ];
    }

    private function derivedLifecycleState(string $state): string
    {
        return match ($state) {
            WorkspaceSubscription::STATE_TRIAL => WorkspaceCommercialLifecycleResolver::STATE_TRIAL,
            WorkspaceSubscription::STATE_ACTIVE => WorkspaceCommercialLifecycleResolver::STATE_ACTIVE_PAID,
            WorkspaceSubscription::STATE_PAST_DUE => WorkspaceCommercialLifecycleResolver::STATE_GRACE,
            WorkspaceSubscription::STATE_CANCEL_AT_PERIOD_END => WorkspaceCommercialLifecycleResolver::STATE_ACTIVE_PAID,
            WorkspaceSubscription::STATE_ENDED => WorkspaceCommercialLifecycleResolver::STATE_SUSPENDED_READ_ONLY,
            default => WorkspaceCommercialLifecycleResolver::STATE_ACTIVE_PAID,
        };
    }

    private function keyDateLabel(string $state): ?string
    {
        return match ($state) {
            WorkspaceSubscription::STATE_TRIAL => 'Trial ends',
            WorkspaceSubscription::STATE_ACTIVE,
            WorkspaceSubscription::STATE_PAST_DUE,
            WorkspaceSubscription::STATE_CANCEL_AT_PERIOD_END,
            WorkspaceSubscription::STATE_ENDED => 'Current period ends',
            default => null,
        };
    }

    private function keyDateForSubscription(WorkspaceSubscription $subscription, string $state): ?CarbonInterface
    {
        return match ($state) {
            WorkspaceSubscription::STATE_TRIAL => $subscription->trial_ends_at,
            WorkspaceSubscription::STATE_ACTIVE,
            WorkspaceSubscription::STATE_PAST_DUE,
            WorkspaceSubscription::STATE_CANCEL_AT_PERIOD_END,
            WorkspaceSubscription::STATE_ENDED => $subscription->current_period_ends_at,
            default => null,
        };
    }

    private function needsReview(string $state, ?CarbonInterface $keyDate): bool
    {
        if (! in_array($state, [WorkspaceSubscription::STATE_TRIAL, WorkspaceSubscription::STATE_CANCEL_AT_PERIOD_END], true)) {
            return false;
        }

        return $keyDate instanceof CarbonInterface && $keyDate->isPast();
    }
}