<?php

namespace App\Services;

use App\Models\Plan;
use App\Models\Subscription;
use App\Models\SubscriptionChange;
use App\Services\Payments\PaymentOrchestrator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class SubscriptionMigrationService
{
    public function __construct(
        private PaymentOrchestrator $orchestrator
    ) {}

    /**
     * Migrate subscription to a new plan
     */
    public function migrateToPlan(Subscription $subscription, Plan $newPlan, string $reason = ''): bool
    {
        try {
            DB::beginTransaction();

            $oldPlan = $subscription->plan;
            $oldValues = [
                'plan_id' => $subscription->plan_id,
                'plan_name' => $oldPlan?->name,
                'price' => $oldPlan?->price,
            ];

            // Update subscription with new plan
            $subscription->update([
                'plan_id' => $newPlan->id,
                'updated_at' => now(),
            ]);

            // Record the change
            SubscriptionChange::createRecord(
                $subscription,
                'plan_change',
                "Migrated from {$oldPlan?->name} to {$newPlan->name}",
                $oldValues,
                [
                    'plan_id' => $newPlan->id,
                    'plan_name' => $newPlan->name,
                    'price' => $newPlan->price,
                ],
                $reason
            );

            DB::commit();

            Log::info('Subscription plan migration completed', [
                'subscription_id' => $subscription->id,
                'old_plan_id' => $oldPlan?->id,
                'new_plan_id' => $newPlan->id,
                'reason' => $reason,
            ]);

            return true;

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Subscription plan migration failed', [
                'subscription_id' => $subscription->id,
                'new_plan_id' => $newPlan->id,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    /**
     * Migrate subscription to a new provider
     */
    public function migrateToProvider(Subscription $subscription, string $newProvider, array $providerData = []): bool
    {
        try {
            DB::beginTransaction();

            $oldProvider = $subscription->provider;
            $oldValues = [
                'provider' => $oldProvider,
                'provider_subscription_id' => $subscription->provider_subscription_id,
            ];

            // Cancel subscription with old provider if needed
            if ($oldProvider && $subscription->isActive()) {
                $this->orchestrator->cancelSubscription($subscription, 'Provider migration');
            }

            // Update subscription with new provider
            $subscription->update([
                'provider' => $newProvider,
                'provider_subscription_id' => $providerData['subscription_id'] ?? null,
                'provider_data' => array_merge($subscription->provider_data ?? [], $providerData),
                'last_provider_sync' => now(),
            ]);

            // Record the change
            SubscriptionChange::createRecord(
                $subscription,
                'provider_change',
                "Migrated from {$oldProvider} to {$newProvider}",
                $oldValues,
                [
                    'provider' => $newProvider,
                    'provider_subscription_id' => $providerData['subscription_id'] ?? null,
                ],
                'Provider migration for better service'
            );

            DB::commit();

            Log::info('Subscription provider migration completed', [
                'subscription_id' => $subscription->id,
                'old_provider' => $oldProvider,
                'new_provider' => $newProvider,
            ]);

            return true;

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Subscription provider migration failed', [
                'subscription_id' => $subscription->id,
                'new_provider' => $newProvider,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    /**
     * Pause subscription
     */
    public function pauseSubscription(Subscription $subscription, string $reason = ''): bool
    {
        try {
            DB::beginTransaction();

            $oldValues = [
                'status' => $subscription->status,
                'paused_at' => null,
            ];

            // Update subscription status
            $subscription->update([
                'status' => 'paused',
                'paused_at' => now(),
            ]);

            // Record the change
            SubscriptionChange::createRecord(
                $subscription,
                'pause',
                'Subscription paused',
                $oldValues,
                [
                    'status' => 'paused',
                    'paused_at' => now()->format('Y-m-d H:i:s'),
                ],
                $reason
            );

            DB::commit();

            Log::info('Subscription paused', [
                'subscription_id' => $subscription->id,
                'reason' => $reason,
            ]);

            return true;

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to pause subscription', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    /**
     * Resume subscription
     */
    public function resumeSubscription(Subscription $subscription, string $reason = ''): bool
    {
        try {
            DB::beginTransaction();

            $oldValues = [
                'status' => $subscription->status,
                'paused_at' => $subscription->paused_at,
                'resumed_at' => null,
            ];

            // Update subscription status
            $subscription->update([
                'status' => 'active',
                'resumed_at' => now(),
            ]);

            // Record the change
            SubscriptionChange::createRecord(
                $subscription,
                'resume',
                'Subscription resumed',
                $oldValues,
                [
                    'status' => 'active',
                    'resumed_at' => now()->format('Y-m-d H:i:s'),
                ],
                $reason
            );

            DB::commit();

            Log::info('Subscription resumed', [
                'subscription_id' => $subscription->id,
                'reason' => $reason,
            ]);

            return true;

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to resume subscription', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    /**
     * Bulk migrate subscriptions
     */
    public function bulkMigrate(array $subscriptionIds, callable $migrationCallback): array
    {
        $results = [
            'success' => 0,
            'failed' => 0,
            'errors' => [],
        ];

        foreach ($subscriptionIds as $subscriptionId) {
            try {
                $subscription = Subscription::findOrFail($subscriptionId);

                if ($migrationCallback($subscription)) {
                    $results['success']++;
                } else {
                    $results['failed']++;
                    $results['errors'][] = "Migration failed for subscription {$subscriptionId}";
                }
            } catch (\Exception $e) {
                $results['failed']++;
                $results['errors'][] = "Error processing subscription {$subscriptionId}: {$e->getMessage()}";
            }
        }

        return $results;
    }

    /**
     * Get migration history for a subscription
     */
    public function getMigrationHistory(Subscription $subscription): \Illuminate\Database\Eloquent\Collection
    {
        return $subscription->subscriptionChanges()
            ->whereIn('change_type', ['plan_change', 'provider_change', 'migration'])
            ->orderBy('effective_at', 'desc')
            ->get();
    }

    /**
     * Get pending migrations
     */
    public function getPendingMigrations(): \Illuminate\Database\Eloquent\Collection
    {
        return SubscriptionChange::query()
            ->whereIn('change_type', ['plan_change', 'provider_change', 'migration'])
            ->pending()
            ->with(['subscription', 'user'])
            ->orderBy('effective_at', 'asc')
            ->get();
    }

    /**
     * Process pending migrations
     */
    public function processPendingMigrations(): int
    {
        $pending = $this->getPendingMigrations();
        $processedCount = 0;

        foreach ($pending as $change) {
            try {
                // Here you would implement the actual migration logic
                // based on the change type and data
                $change->markAsProcessed();
                $processedCount++;
            } catch (\Exception $e) {
                Log::error('Failed to process pending migration', [
                    'change_id' => $change->id,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        return $processedCount;
    }
}
