<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\EventPackageAddon;
use App\Services\Paddle\Exceptions\PaddleException;
use App\Services\Paddle\PaddleCustomerPortalService;
use App\Services\Paddle\PaddleCustomerService;
use App\Services\Paddle\PaddleTransactionService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;

class TenantBillingController extends Controller
{
    public function __construct(
        private readonly PaddleTransactionService $paddleTransactions,
        private readonly PaddleCustomerService $paddleCustomers,
        private readonly PaddleCustomerPortalService $portalSessions,
    ) {}

    public function transactions(Request $request): JsonResponse
    {
        $tenant = $request->attributes->get('tenant');

        if (! $tenant) {
            return response()->json([
                'data' => [],
                'message' => 'Tenant not found.',
            ], 404);
        }

        if (! $tenant->paddle_customer_id) {
            try {
                $this->paddleCustomers->ensureCustomerId($tenant);
            } catch (\Throwable $exception) {
                Log::warning('Failed to resolve Paddle customer for tenant', [
                    'tenant_id' => $tenant->id,
                    'error' => $exception->getMessage(),
                ]);

                return response()->json([
                    'data' => [],
                    'message' => 'Failed to resolve Paddle customer.',
                ], 502);
            }
        }

        $cursor = $request->query('cursor');
        $perPage = (int) $request->query('per_page', 25);

        $query = [
            'per_page' => max(1, min($perPage, 100)),
        ];

        if ($cursor) {
            $query['after'] = $cursor;
        }

        try {
            $result = $this->paddleTransactions->listForCustomer($tenant->paddle_customer_id, $query);
        } catch (\Throwable $exception) {
            Log::warning('Failed to load Paddle transactions', [
                'tenant_id' => $tenant->id,
                'error' => $exception->getMessage(),
            ]);

            return response()->json([
                'data' => [],
                'message' => 'Failed to load Paddle transactions.',
            ], 502);
        }

        return response()->json([
            'data' => $result['data'],
            'meta' => $result['meta'],
        ]);
    }

    public function addons(Request $request): JsonResponse
    {
        $tenant = $request->attributes->get('tenant');

        if (! $tenant) {
            return response()->json([
                'data' => [],
                'message' => 'Tenant not found.',
            ], 404);
        }

        $perPage = max(1, min((int) $request->query('per_page', 25), 100));
        $page = max(1, (int) $request->query('page', 1));

        $paginator = EventPackageAddon::query()
            ->where('tenant_id', $tenant->id)
            ->with(['event:id,name,slug'])
            ->orderByDesc('purchased_at')
            ->orderByDesc('created_at')
            ->paginate($perPage, ['*'], 'page', $page);

        $data = $paginator->getCollection()->map(function (EventPackageAddon $addon) {
            return [
                'id' => $addon->id,
                'addon_key' => $addon->addon_key,
                'label' => $addon->metadata['label'] ?? null,
                'quantity' => (int) ($addon->quantity ?? 1),
                'status' => $addon->status,
                'amount' => $addon->amount !== null ? (float) $addon->amount : null,
                'currency' => $addon->currency,
                'extra_photos' => (int) $addon->extra_photos,
                'extra_guests' => (int) $addon->extra_guests,
                'extra_gallery_days' => (int) $addon->extra_gallery_days,
                'purchased_at' => $addon->purchased_at?->toIso8601String(),
                'receipt_url' => Arr::get($addon->receipt_payload, 'receipt_url'),
                'event' => $addon->event ? [
                    'id' => $addon->event->id,
                    'slug' => $addon->event->slug,
                    'name' => $addon->event->name,
                ] : null,
            ];
        })->values();

        return response()->json([
            'data' => $data,
            'meta' => [
                'current_page' => $paginator->currentPage(),
                'last_page' => $paginator->lastPage(),
                'per_page' => $paginator->perPage(),
                'total' => $paginator->total(),
            ],
        ]);
    }

    public function portal(Request $request): JsonResponse
    {
        $tenant = $request->attributes->get('tenant');

        if (! $tenant) {
            return response()->json([
                'message' => 'Tenant not found.',
            ], 404);
        }

        $customerId = null;

        try {
            $customerId = $this->paddleCustomers->ensureCustomerId($tenant);

            Log::debug('Creating Paddle customer portal session', [
                'tenant_id' => $tenant->id,
                'paddle_customer_id' => $customerId,
                'paddle_environment' => config('paddle.environment'),
                'paddle_base_url' => config('paddle.base_url'),
            ]);

            $session = $this->portalSessions->createSession($customerId);
        } catch (\Throwable $exception) {
            $context = [
                'tenant_id' => $tenant->id,
                'paddle_customer_id' => $customerId ?? $tenant->paddle_customer_id,
                'error' => $exception->getMessage(),
                'paddle_environment' => config('paddle.environment'),
                'paddle_base_url' => config('paddle.base_url'),
            ];

            if ($exception instanceof PaddleException) {
                $context['paddle_status'] = $exception->status();
                $context['paddle_error_code'] = Arr::get($exception->context(), 'error.code');
                $context['paddle_error_message'] = Arr::get($exception->context(), 'error.message');
                $context['paddle_error_detail'] = Arr::get($exception->context(), 'error.detail');
                $context['paddle_error_doc_url'] = Arr::get($exception->context(), 'error.documentation_url');
                $context['paddle_request_id'] = Arr::get($exception->context(), 'meta.request_id');
                $context['paddle_errors'] = Arr::get($exception->context(), 'error.errors');
            }

            Log::warning('Failed to create Paddle customer portal session', [
                ...$context,
            ]);

            return response()->json([
                'message' => 'Failed to create Paddle customer portal session.',
            ], 502);
        }

        $url = Arr::get($session, 'data.urls.general.overview')
            ?? Arr::get($session, 'data.urls.general')
            ?? Arr::get($session, 'urls.general.overview')
            ?? Arr::get($session, 'urls.general');

        if (! $url) {
            $sessionData = Arr::get($session, 'data');
            $sessionUrls = Arr::get($session, 'data.urls') ?? Arr::get($session, 'urls');

            Log::warning('Paddle customer portal session missing URL', [
                'tenant_id' => $tenant->id,
                'paddle_customer_id' => $customerId ?? $tenant->paddle_customer_id,
                'paddle_environment' => config('paddle.environment'),
                'paddle_base_url' => config('paddle.base_url'),
                'session_keys' => array_keys($session),
                'session_data_keys' => is_array($sessionData) ? array_keys($sessionData) : null,
                'session_url_keys' => is_array($sessionUrls) ? array_keys($sessionUrls) : null,
            ]);

            return response()->json([
                'message' => 'Paddle customer portal session missing URL.',
            ], 502);
        }

        return response()->json([
            'url' => $url,
        ]);
    }
}
