<?php

namespace App\Services\Payments\Providers;

use App\Contracts\Payments\PaymentProviderContract;
use App\Models\Plan;
use App\Models\Subscription;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class LemonSqueezyProvider implements PaymentProviderContract
{
    protected array $config;

    protected ?string $apiKey;

    public function __construct(array $config = [])
    {
        $this->config = array_merge([
            'api_key' => config('services.lemon_squeezy.api_key'),
            'store_id' => config('services.lemon_squeezy.store_id'),
            'webhook_secret' => config('services.lemon_squeezy.webhook_secret'),
            'success_url' => route('payment.success'),
            'cancel_url' => route('payment.cancel'),
            'api_version' => 'v1',
        ], $config);

        $this->apiKey = $this->config['api_key'] ?? null;
    }

    public function getName(): string
    {
        return 'lemon_squeezy';
    }

    public function isActive(): bool
    {
        return ! empty($this->apiKey) && ! empty($this->config['store_id']);
    }

    public function createSubscription(User $user, Plan $plan, array $options = []): array
    {
        try {
            $variantId = $this->getOrCreateVariant($plan);

            $checkoutData = [
                'store_id' => $this->config['store_id'],
                'variant_id' => $variantId,
                'customer_email' => $user->email,
                'success_url' => $options['success_url'] ?? $this->config['success_url'],
                'cancel_url' => $options['cancel_url'] ?? $this->config['cancel_url'],
                'embed' => false,
                'invoice_grace_period' => 0,
            ];

            if (! empty($options['trial_days'])) {
                $checkoutData['trial_period'] = $options['trial_days'];
            }

            if (! empty($options['coupon_code'])) {
                $checkoutData['discount_code'] = $options['coupon_code'];
            }

            // Add custom data for tracking
            $checkoutData['custom_data'] = [
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'provider' => 'lemon_squeezy',
            ];

            $response = $this->makeRequest('POST', '/checkouts', $checkoutData);

            return [
                'provider_subscription_id' => $response['data']['id'],
                'status' => 'pending',
                'checkout_url' => $response['data']['attributes']['url'],
                'type' => 'checkout_session',
            ];

        } catch (\Exception $e) {
            Log::error('Lemon Squeezy subscription creation failed', [
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function cancelSubscription(Subscription $subscription, string $reason = ''): bool
    {
        try {
            $subscriptionId = $subscription->provider_subscription_id;

            if (! $subscriptionId) {
                throw new \Exception('No Lemon Squeezy subscription ID found');
            }

            // Cancel at period end (graceful cancellation)
            $response = $this->makeRequest('DELETE', "/subscriptions/{$subscriptionId}", [
                'cancel_at_period_end' => true,
            ]);

            return true;

        } catch (\Exception $e) {
            Log::error('Lemon Squeezy subscription cancellation failed', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function updateSubscription(Subscription $subscription, Plan $newPlan): array
    {
        try {
            $subscriptionId = $subscription->provider_subscription_id;
            $newVariantId = $this->getOrCreateVariant($newPlan);

            // Update subscription variant
            $response = $this->makeRequest('PATCH', "/subscriptions/{$subscriptionId}", [
                'variant_id' => $newVariantId,
            ]);

            return [
                'provider_subscription_id' => $subscriptionId,
                'status' => $response['data']['attributes']['status'],
                'new_variant_id' => $newVariantId,
            ];

        } catch (\Exception $e) {
            Log::error('Lemon Squeezy subscription update failed', [
                'subscription_id' => $subscription->id,
                'new_plan_id' => $newPlan->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function pauseSubscription(Subscription $subscription): bool
    {
        try {
            $subscriptionId = $subscription->provider_subscription_id;

            // Pause subscription
            $response = $this->makeRequest('PATCH', "/subscriptions/{$subscriptionId}", [
                'pause' => [
                    'mode' => 'void',
                ],
            ]);

            return true;

        } catch (\Exception $e) {
            Log::error('Lemon Squeezy subscription pause failed', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function resumeSubscription(Subscription $subscription): bool
    {
        try {
            $subscriptionId = $subscription->provider_subscription_id;

            // Unpause subscription
            $response = $this->makeRequest('PATCH', "/subscriptions/{$subscriptionId}", [
                'pause' => null,
                'cancel_at_period_end' => false,
            ]);

            return true;

        } catch (\Exception $e) {
            Log::error('Lemon Squeezy subscription resume failed', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function getSubscriptionDetails(string $providerSubscriptionId): array
    {
        try {
            $response = $this->makeRequest('GET', "/subscriptions/{$providerSubscriptionId}");

            $data = $response['data']['attributes'];

            return [
                'id' => $data['id'],
                'status' => $data['status'],
                'customer_id' => $data['customer_id'],
                'order_id' => $data['order_id'],
                'product_id' => $data['product_id'],
                'variant_id' => $data['variant_id'],
                'created_at' => $data['created_at'],
                'updated_at' => $data['updated_at'],
                'trial_ends_at' => $data['trial_ends_at'] ?? null,
                'renews_at' => $data['renews_at'] ?? null,
                'ends_at' => $data['ends_at'] ?? null,
                'cancelled_at' => $data['cancelled_at'] ?? null,
            ];

        } catch (\Exception $e) {
            Log::error('Lemon Squeezy subscription details retrieval failed', [
                'subscription_id' => $providerSubscriptionId,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function createCheckoutSession(User $user, Plan $plan, array $options = []): array
    {
        return $this->createSubscription($user, $plan, $options);
    }

    public function createCustomerPortalSession(User $user): array
    {
        try {
            // Lemon Squeezy doesn't have a customer portal like Stripe
            // Instead, we can redirect to the customer's orders page
            return [
                'portal_url' => 'https://app.lemonsqueezy.com/my-orders',
                'message' => 'Lemon Squeezy customer portal',
            ];

        } catch (\Exception $e) {
            Log::error('Lemon Squeezy customer portal creation failed', [
                'user_id' => $user->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function processWebhook(Request $request): array
    {
        try {
            $payload = $request->getContent();
            $eventData = json_decode($payload, true);

            $eventType = $eventData['meta']['event_name'] ?? 'unknown';
            $result = [
                'event_type' => $eventType,
                'processed' => false,
                'data' => [],
            ];

            switch ($eventType) {
                case 'subscription_created':
                    $result = $this->handleSubscriptionCreated($eventData);
                    break;
                case 'subscription_updated':
                    $result = $this->handleSubscriptionUpdated($eventData);
                    break;
                case 'subscription_cancelled':
                    $result = $this->handleSubscriptionCancelled($eventData);
                    break;
                case 'subscription_resumed':
                    $result = $this->handleSubscriptionResumed($eventData);
                    break;
                case 'order_created':
                    $result = $this->handleOrderCreated($eventData);
                    break;
                case 'order_payment_succeeded':
                    $result = $this->handleOrderPaymentSucceeded($eventData);
                    break;
                default:
                    Log::info('Unhandled Lemon Squeezy webhook event', ['event_type' => $eventType]);
            }

            return $result;

        } catch (\Exception $e) {
            Log::error('Lemon Squeezy webhook processing failed', [
                'error' => $e->getMessage(),
                'payload' => $request->getContent(),
            ]);
            throw $e;
        }
    }

    public function validateWebhook(Request $request): bool
    {
        try {
            $signature = $request->header('X-Signature');
            $payload = $request->getContent();

            if (! $signature || ! $this->config['webhook_secret']) {
                return false;
            }

            $expectedSignature = hash_hmac('sha256', $payload, $this->config['webhook_secret']);

            return hash_equals($signature, $expectedSignature);

        } catch (\Exception $e) {
            Log::warning('Lemon Squeezy webhook validation failed', [
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    public function getConfiguration(): array
    {
        return $this->config;
    }

    public function syncSubscriptionStatus(Subscription $subscription): array
    {
        return $this->getSubscriptionDetails($subscription->provider_subscription_id);
    }

    public function getPaymentMethodDetails(string $paymentMethodId): array
    {
        try {
            $response = $this->makeRequest('GET', "/payment-methods/{$paymentMethodId}");

            $data = $response['data']['attributes'];

            return [
                'id' => $data['id'],
                'type' => $data['type'],
                'card' => [
                    'last4' => $data['last4'] ?? null,
                    'brand' => $data['brand'] ?? null,
                    'exp_month' => $data['exp_month'] ?? null,
                    'exp_year' => $data['exp_year'] ?? null,
                ],
                'created_at' => $data['created_at'],
            ];

        } catch (\Exception $e) {
            Log::error('Lemon Squeezy payment method details retrieval failed', [
                'payment_method_id' => $paymentMethodId,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function processRefund(string $orderId, float $amount, string $reason = ''): array
    {
        try {
            $response = $this->makeRequest('POST', "/orders/{$orderId}/refunds", [
                'amount' => (int) ($amount * 100), // Lemon Squeezy uses cents
                'reason' => $reason ?: 'requested_by_customer',
                'note' => 'Refund processed via unified payment system',
            ]);

            return [
                'refund_id' => $response['data']['id'],
                'amount' => $response['data']['attributes']['amount'] / 100,
                'status' => $response['data']['attributes']['status'],
                'created_at' => $response['data']['attributes']['created_at'],
            ];

        } catch (\Exception $e) {
            Log::error('Lemon Squeezy refund processing failed', [
                'order_id' => $orderId,
                'amount' => $amount,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function getTransactionHistory(User $user, array $filters = []): array
    {
        try {
            // Get all orders for the customer
            $response = $this->makeRequest('GET', '/orders', [
                'filter' => [
                    'customer_email' => $user->email,
                ],
                'page' => [
                    'limit' => $filters['limit'] ?? 100,
                ],
            ]);

            $transactions = [];

            foreach ($response['data'] as $order) {
                $attributes = $order['attributes'];

                $transactions[] = [
                    'id' => $attributes['id'],
                    'order_number' => $attributes['order_number'],
                    'amount' => $attributes['total'] / 100,
                    'currency' => $attributes['currency'],
                    'status' => $attributes['status'],
                    'created_at' => $attributes['created_at'],
                    'refunded' => $attributes['refunded'] ?? false,
                    'customer_email' => $attributes['customer_email'],
                ];
            }

            return $transactions;

        } catch (\Exception $e) {
            Log::error('Lemon Squeezy transaction history retrieval failed', [
                'user_id' => $user->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function calculateFees(float $amount): array
    {
        // Lemon Squeezy fees: 5% + $0.50 flat fee
        $fixedFee = 0.50;
        $percentageFee = 5.0;

        $percentageAmount = ($amount * $percentageFee) / 100;
        $totalFee = $fixedFee + $percentageAmount;

        return [
            'fixed_fee' => $fixedFee,
            'percentage_fee' => $percentageAmount,
            'total_fee' => $totalFee,
            'net_amount' => $amount - $totalFee,
        ];
    }

    public function getSupportedCurrencies(): array
    {
        return [
            'USD', 'EUR', 'GBP', 'CAD', 'AUD', 'CHF', 'SEK', 'NOK', 'DKK',
            'PLN', 'CZK', 'HUF', 'RON', 'BGN', 'HRK', 'RUB', 'TRY', 'MXN',
            'BRL', 'ARS', 'CLP', 'COP', 'PEN', 'UYU', 'JPY', 'SGD', 'HKD',
            'INR', 'MYR', 'THB', 'PHP', 'TWD', 'KRW', 'CNY', 'NZD',
            'ZAR', 'NGN', 'KES', 'GHS', 'EGP', 'MAD', 'TND', 'DZD',
        ];
    }

    public function supportsRecurring(): bool
    {
        return true;
    }

    public function supportsOneTime(): bool
    {
        return true;
    }

    // Helper methods
    protected function makeRequest(string $method, string $endpoint, array $data = []): array
    {
        $url = "https://api.lemonsqueezy.com/{$this->config['api_version']}{$endpoint}";

        $headers = [
            'Accept' => 'application/json',
            'Content-Type' => 'application/json',
            'Authorization' => 'Bearer '.$this->apiKey,
        ];

        $response = Http::withHeaders($headers)
            ->asJson()
            ->send($method, $url, $data);

        if (! $response->successful()) {
            throw new \Exception("Lemon Squeezy API request failed: {$response->status()} - {$response->body()}");
        }

        return $response->json();
    }

    protected function getOrCreateVariant(Plan $plan): string
    {
        // Check if plan already has a Lemon Squeezy variant ID
        if (! empty($plan->details['lemon_squeezy_variant_id'])) {
            return $plan->details['lemon_squeezy_variant_id'];
        }

        // Create product if it doesn't exist
        $productId = $this->getOrCreateProduct($plan);

        // Create variant
        $variantData = [
            'product_id' => $productId,
            'name' => $plan->name,
            'description' => $plan->description ?? '',
            'price' => $plan->price * 100, // Convert to cents
            'price_formatted' => $this->formatPrice($plan->price),
        ];

        if ($plan->monthly_billing) {
            $variantData['interval'] = 'month';
            $variantData['interval_count'] = 1;
        } else {
            $variantData['interval'] = 'one_time';
        }

        $response = $this->makeRequest('POST', '/variants', $variantData);
        $variantId = $response['data']['id'];

        // Update plan with new variant ID
        $planDetails = $plan->details ?? [];
        $planDetails['lemon_squeezy_variant_id'] = $variantId;
        $plan->update(['details' => $planDetails]);

        return $variantId;
    }

    protected function getOrCreateProduct(Plan $plan): string
    {
        // Check if plan already has a Lemon Squeezy product ID
        if (! empty($plan->details['lemon_squeezy_product_id'])) {
            return $plan->details['lemon_squeezy_product_id'];
        }

        // Create product
        $productData = [
            'store_id' => $this->config['store_id'],
            'name' => $plan->name,
            'description' => $plan->description ?? '',
            'slug' => strtolower(str_replace(' ', '-', $plan->name)),
        ];

        $response = $this->makeRequest('POST', '/products', $productData);
        $productId = $response['data']['id'];

        // Update plan with new product ID
        $planDetails = $plan->details ?? [];
        $planDetails['lemon_squeezy_product_id'] = $productId;
        $plan->update(['details' => $planDetails]);

        return $productId;
    }

    protected function formatPrice(float $price): string
    {
        // Format price based on currency
        $currency = $this->config['currency'] ?? 'USD';

        switch ($currency) {
            case 'USD':
            case 'CAD':
            case 'AUD':
                return '$'.number_format($price, 2);
            case 'EUR':
                return '€'.number_format($price, 2);
            case 'GBP':
                return '£'.number_format($price, 2);
            default:
                return number_format($price, 2).' '.$currency;
        }
    }

    // Webhook handlers
    protected function handleSubscriptionCreated(array $eventData): array
    {
        $attributes = $eventData['data']['attributes'];

        return [
            'event_type' => $eventData['meta']['event_name'],
            'processed' => true,
            'data' => [
                'subscription_id' => $attributes['id'],
                'customer_id' => $attributes['customer_id'],
                'product_id' => $attributes['product_id'],
                'variant_id' => $attributes['variant_id'],
                'status' => $attributes['status'],
            ],
        ];
    }

    protected function handleSubscriptionUpdated(array $eventData): array
    {
        $attributes = $eventData['data']['attributes'];

        return [
            'event_type' => $eventData['meta']['event_name'],
            'processed' => true,
            'data' => [
                'subscription_id' => $attributes['id'],
                'status' => $attributes['status'],
                'renews_at' => $attributes['renews_at'] ?? null,
            ],
        ];
    }

    protected function handleSubscriptionCancelled(array $eventData): array
    {
        $attributes = $eventData['data']['attributes'];

        return [
            'event_type' => $eventData['meta']['event_name'],
            'processed' => true,
            'data' => [
                'subscription_id' => $attributes['id'],
                'status' => 'cancelled',
                'cancelled_at' => $attributes['cancelled_at'],
            ],
        ];
    }

    protected function handleSubscriptionResumed(array $eventData): array
    {
        $attributes = $eventData['data']['attributes'];

        return [
            'event_type' => $eventData['meta']['event_name'],
            'processed' => true,
            'data' => [
                'subscription_id' => $attributes['id'],
                'status' => $attributes['status'],
            ],
        ];
    }

    protected function handleOrderCreated(array $eventData): array
    {
        $attributes = $eventData['data']['attributes'];

        return [
            'event_type' => $eventData['meta']['event_name'],
            'processed' => true,
            'data' => [
                'order_id' => $attributes['id'],
                'order_number' => $attributes['order_number'],
                'customer_email' => $attributes['customer_email'],
                'total' => $attributes['total'],
                'currency' => $attributes['currency'],
            ],
        ];
    }

    protected function handleOrderPaymentSucceeded(array $eventData): array
    {
        $attributes = $eventData['data']['attributes'];

        return [
            'event_type' => $eventData['meta']['event_name'],
            'processed' => true,
            'data' => [
                'order_id' => $attributes['id'],
                'order_number' => $attributes['order_number'],
                'total' => $attributes['total'],
                'status' => 'paid',
            ],
        ];
    }

    // Additional interface methods
    public function getSubscriptionMetadata(Subscription $subscription): array
    {
        return $subscription->provider_data['metadata'] ?? [];
    }

    public function updateSubscriptionMetadata(Subscription $subscription, array $metadata): bool
    {
        // Lemon Squeezy doesn't support metadata on subscriptions directly
        // Store in our local provider_data instead
        $providerData = $subscription->provider_data ?? [];
        $providerData['metadata'] = $metadata;
        $subscription->update(['provider_data' => $providerData]);

        return true;
    }

    public function startTrial(Subscription $subscription, int $trialDays): bool
    {
        // Lemon Squeezy handles trials via variant configuration
        // This would require creating a trial variant and switching
        return true;
    }

    public function applyCoupon(Subscription $subscription, string $couponCode): array
    {
        try {
            // Apply discount code to subscription
            $subscriptionId = $subscription->provider_subscription_id;

            $response = $this->makeRequest('POST', "/subscriptions/{$subscriptionId}/discounts", [
                'discount_code' => $couponCode,
            ]);

            return [
                'discount_id' => $response['data']['id'],
                'amount' => $response['data']['attributes']['amount'] / 100,
                'type' => $response['data']['attributes']['type'],
            ];

        } catch (\Exception $e) {
            Log::error('Failed to apply Lemon Squeezy coupon', [
                'subscription_id' => $subscription->id,
                'coupon_code' => $couponCode,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function removeCoupon(Subscription $subscription): bool
    {
        try {
            $subscriptionId = $subscription->provider_subscription_id;

            // Get and delete all discounts
            $discounts = $this->makeRequest('GET', "/subscriptions/{$subscriptionId}/discounts");

            foreach ($discounts['data'] as $discount) {
                $this->makeRequest('DELETE', "/discounts/{$discount['id']}");
            }

            return true;

        } catch (\Exception $e) {
            Log::error('Failed to remove Lemon Squeezy coupon', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    public function getUpcomingInvoice(Subscription $subscription): array
    {
        try {
            $subscriptionId = $subscription->provider_subscription_id;

            $response = $this->makeRequest('GET', "/subscriptions/{$subscriptionId}");
            $attributes = $response['data']['attributes'];

            return [
                'amount_due' => $attributes['renews_at'] ? 0 : $attributes['subtotal'] / 100,
                'currency' => $attributes['currency'],
                'next_payment_date' => $attributes['renews_at'],
            ];

        } catch (\Exception $e) {
            Log::error('Failed to get Lemon Squeezy upcoming invoice', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function retryFailedPayment(Subscription $subscription): array
    {
        // Lemon Squeezy handles failed payments automatically
        // We can trigger a subscription sync instead
        return $this->syncSubscriptionStatus($subscription);
    }

    public function canModifySubscription(Subscription $subscription): bool
    {
        try {
            $details = $this->getSubscriptionDetails($subscription->provider_subscription_id);

            return in_array($details['status'], ['active', 'trialing', 'paused']);
        } catch (\Exception $e) {
            return false;
        }
    }

    public function getCancellationTerms(Subscription $subscription): array
    {
        return [
            'immediate_cancellation' => false, // Lemon Squeezy cancels at period end
            'refund_policy' => 'as_per_terms',
            'cancellation_effective' => 'period_end',
            'billing_cycle_proration' => true,
        ];
    }

    public function exportSubscriptionData(Subscription $subscription): array
    {
        return [
            'provider' => 'lemon_squeezy',
            'provider_subscription_id' => $subscription->provider_subscription_id,
            'data' => $subscription->provider_data,
        ];
    }

    public function importSubscriptionData(User $user, array $subscriptionData): array
    {
        // Import to Lemon Squeezy - would require creating matching products/variants
        throw new \Exception('Import to Lemon Squeezy not implemented');
    }
}
