<?php

namespace App\Http\Controllers;

use App\Models\Family;
use App\Models\Plan;
use App\Models\Subscription;
use App\Services\SubscriptionService;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Validation\Rule;
use InvalidArgumentException;

class FamilySubscriptionController extends Controller
{
    public function __construct(private SubscriptionService $subscriptions)
    {
    }

    public function preview(Request $request, Family $family)
    {
        $this->authorize('manageSubscription', $family);

        $data = $request->validate([
            'plan_id' => ['required', 'integer', 'exists:plans,id'],
            'driver' => ['nullable', 'string'],
            'options' => ['nullable', 'array'],
        ]);

        $plan = Plan::findOrFail($data['plan_id']);

        $preview = $this->subscriptions->preview(
            $family,
            $plan,
            Arr::get($data, 'options', []),
            $request,
            Arr::get($data, 'driver')
        );

        return response()->json($preview);
    }

    public function store(Request $request, Family $family)
    {
        $this->authorize('manageSubscription', $family);

        $data = $request->validate([
            'plan_id' => ['required', 'integer', 'exists:plans,id'],
            'driver' => ['nullable', 'string'],
            'options' => ['nullable', 'array'],
        ]);

        $plan = Plan::findOrFail($data['plan_id']);

        $subscription = $this->subscriptions->create(
            $family,
            $plan,
            $data,
            $request,
            Arr::get($data, 'driver')
        );

        return response()->json($subscription, 201);
    }

    public function update(Request $request, Family $family, Subscription $subscription)
    {
        $this->authorize('manageSubscription', $family);
        $this->assertSubscriptionBelongsToFamily($family, $subscription);

        $data = $request->validate([
            'plan_id' => ['required', 'integer', 'exists:plans,id'],
            'driver' => ['nullable', 'string'],
            'options' => ['nullable', 'array'],
        ]);

        $plan = Plan::findOrFail($data['plan_id']);

        $updated = $this->subscriptions->swap(
            $family,
            $subscription,
            $plan,
            $data,
            $request,
            Arr::get($data, 'driver')
        );

        return response()->json($updated);
    }

    public function cancel(Request $request, Family $family, Subscription $subscription)
    {
        $this->authorize('manageSubscription', $family);
        $this->assertSubscriptionBelongsToFamily($family, $subscription);

        $data = $request->validate([
            'immediate' => ['nullable', 'boolean'],
            'driver' => ['nullable', 'string'],
        ]);

        $canceled = $this->subscriptions->cancel(
            $family,
            $subscription,
            Arr::get($data, 'immediate', false),
            $request,
            Arr::get($data, 'driver')
        );

        return response()->json($canceled);
    }

    public function resume(Request $request, Family $family, Subscription $subscription)
    {
        $this->authorize('manageSubscription', $family);
        $this->assertSubscriptionBelongsToFamily($family, $subscription);

        $data = $request->validate([
            'driver' => ['nullable', 'string'],
        ]);

        $resumed = $this->subscriptions->resume(
            $family,
            $subscription,
            $request,
            Arr::get($data, 'driver')
        );

        return response()->json($resumed);
    }

    public function invoices(Request $request, Family $family, Subscription $subscription)
    {
        $this->authorize('viewSubscription', $family);
        $this->assertSubscriptionBelongsToFamily($family, $subscription);

        $perPage = (int) $request->integer('per_page', 20);
        $perPage = $perPage > 0 ? min($perPage, 100) : 20;

        $invoices = $this->subscriptions->listInvoices($family, $subscription, $perPage);

        return response()->json($invoices);
    }

    private function assertSubscriptionBelongsToFamily(Family $family, Subscription $subscription): void
    {
        if ($subscription->subscriber_type !== Family::class || (int) $subscription->subscriber_id !== (int) $family->id) {
            throw new InvalidArgumentException('Subscription does not belong to this family.');
        }
    }
}
