<?php

namespace App\Services\Care;

use App\Models\Organization;
use App\Services\Billing\BillingClient;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;

class ProRenewalService
{
    public function __construct(
        private readonly BillingClient $billing,
        private readonly PlanService $plans,
    ) {}

    /** @return Collection<int, Organization> */
    public function dueOrganizations(): Collection
    {
        return Organization::query()
            ->whereIn('settings->plan', ['pro', 'enterprise'])
            ->whereNotNull('settings->plan_expires_at')
            ->get()
            ->filter(fn (Organization $organization) => $this->isDue($organization));
    }

    public function isDue(Organization $organization): bool
    {
        $settings = $organization->settings ?? [];
        $plan = (string) ($settings['plan'] ?? 'free');
        if (! in_array($plan, ['pro', 'enterprise'], true)) {
            return false;
        }
        if (array_key_exists('auto_renew', $settings) && $settings['auto_renew'] === false) {
            return false;
        }
        if (empty($settings['plan_expires_at'])) {
            return false;
        }

        return Carbon::parse($settings['plan_expires_at'])->lte(now());
    }

    public function renewIfDue(Organization $organization): void
    {
        if (! $this->isDue($organization)) {
            return;
        }

        $settings = $organization->settings ?? [];
        $plan = (string) ($settings['plan'] ?? 'free');
        $isEnterprise = $plan === 'enterprise';
        $branches = max(1, $this->plans->activeBranchCount($organization));
        $price = $this->plans->monthlyPriceMinor($organization, $plan);
        $reference = ($isEnterprise ? 'care-enterprise-' : 'care-pro-')
            .$organization->id.'-'.now()->format('YmdHis');

        try {
            $charged = $this->billing->debit(
                $organization->owner_ref,
                $price,
                $isEnterprise ? 'care_enterprise_renewal' : 'care_pro_renewal',
                $reference,
                $isEnterprise
                    ? 'Ladill Care Enterprise — '.$branches.' branch(es) monthly renewal'
                    : 'Ladill Care Pro — '.$branches.' branch(es) monthly renewal',
            );
        } catch (\Throwable) {
            $charged = false;
        }

        if ($charged) {
            $settings['plan'] = $plan;
            $settings['auto_renew'] = true;
            $settings['billed_branches'] = $branches;
            $expiresAt = now()->addDays((int) config('care.pro.period_days', 30));
            $settings['plan_expires_at'] = $expiresAt->toIso8601String();
            unset($settings['plan_renewal_error'], $settings['enterprise_billed_branches']);
            $organization->update(['settings' => $settings]);

            $this->billing->syncSuiteEntitlement(
                $organization->owner_ref,
                $isEnterprise ? 'enterprise' : 'pro',
                'active',
                $reference,
                [
                    'period_starts_at' => now()->toIso8601String(),
                    'period_ends_at' => $expiresAt->toIso8601String(),
                    'source' => 'wallet_debit',
                ],
            );

            return;
        }

        $expires = Carbon::parse($settings['plan_expires_at']);
        $graceEnd = $expires->copy()->addDays((int) config('care.pro.grace_days', 3));
        if ($graceEnd->isPast()) {
            $settings['plan'] = 'free';
            unset($settings['plan_expires_at'], $settings['billed_branches'], $settings['enterprise_billed_branches']);
            $settings['plan_renewal_error'] = 'Suspended after failed renewal.';
            $this->billing->syncSuiteEntitlement(
                $organization->owner_ref,
                'free',
                'cancelled',
                $reference.'-free',
                [
                    'period_starts_at' => now()->toIso8601String(),
                    'period_ends_at' => now()->endOfMonth()->toIso8601String(),
                    'source' => 'wallet_debit',
                ],
            );
        } else {
            $settings['plan_renewal_error'] = 'Renewal failed — top up your wallet.';
            $this->billing->syncSuiteEntitlement(
                $organization->owner_ref,
                $isEnterprise ? 'enterprise' : 'pro',
                'past_due',
                $reference.'-pastdue',
                [
                    'period_starts_at' => now()->toIso8601String(),
                    'period_ends_at' => $graceEnd->toIso8601String(),
                    'source' => 'wallet_debit',
                ],
            );
        }

        $organization->update(['settings' => $settings]);
    }
}
