<?php

namespace App\Console\Commands\Migrations;

use App\Models\InitiativeProject;
use App\Models\Order;
use App\Models\ProjectCharter;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class ProjectCharterMigration extends BaseMigration
{
    protected string $oldTableName = 'sek_project_charters';

    protected string $modelName = 'Project Charters';

    public function migrate(bool $dryRun = false, int $batchSize = 1000, int $startFrom = 0): void
    {
        $oldDb = DB::connection($this->connection);
        $this->processData($oldDb, $dryRun, $startFrom, $batchSize);
    }

    protected function getModelName(): string
    {
        return 'Project Charter';
    }

    protected function getModelClass(): string
    {
        return 'App\\Models\\ProjectCharter';
    }

    protected function createModel(array $data): void
    {
        $oldRecord = $data['old_record'];
        unset($data['old_record']);

        // Create the project charter with unguarded mass assignment to preserve IDs
        ProjectCharter::unguarded(function () use ($data, $oldRecord) {
            // Disable automatic activity logging during creation
            activity()->disableLogging();

            $charter = ProjectCharter::create($data);

            // Re-enable activity logging
            activity()->enableLogging();

            // Create activity logs for approval flow if needed
            $this->createActivityLogs($charter, $oldRecord, $data);

            $this->info("📄 Migrated project charter ID {$charter->getKey()}: {$charter->name} - {$charter->status}");
        });
    }

    protected function processData($oldDb, bool $dryRun, int $startFrom, int $batchSize): void
    {
        $query = $oldDb->table($this->oldTableName)
            ->orderBy('id')
            ->offset($startFrom);

        $totalRecords = $oldDb->table($this->oldTableName)->count();
        $this->info("📊 Found {$totalRecords} project charters to migrate");

        if ($totalRecords === 0) {
            $this->info('✅ No records to migrate');

            return;
        }

        $bar = $this->command->getOutput()->createProgressBar($totalRecords);
        $bar->start();

        $query->chunk($batchSize, function ($oldRecords) use ($dryRun, $bar) {
            foreach ($oldRecords as $oldRecord) {
                $bar->advance();

                $data = $this->mapData($oldRecord);

                // Handle order conflict by removing order_id if already used
                if (! empty($data['order_id'])) {
                    $existingCharterWithOrder = DB::table('project_charters')
                        ->where('order_id', $data['order_id'])
                        ->exists();

                    if ($existingCharterWithOrder) {
                        $this->warn("⚠️  Order ID {$data['order_id']} is already linked to another project charter for charter {$data['id']} - removing order link");
                        $data['order_id'] = null;
                    }
                }

                if ($this->validateData($data)) {
                    try {
                        if (! $dryRun) {
                            $this->createModel($data);
                        }
                        $this->stats['migrated']++;
                        $this->info("✅ Created project charter: {$data['id']} - {$data['name']} ({$data['status']})");
                    } catch (\Exception $e) {
                        $this->stats['errors']++;
                        $this->error("❌ Error creating project charter ID {$oldRecord->id}: {$e->getMessage()}");
                    }
                } else {
                    $this->stats['skipped']++;
                    $this->warn("⚠️  Skipped project charter ID {$oldRecord->id} (validation failed)");
                }
            }
        });

        $bar->finish();
        $this->info('');  // Add newline
    }

    protected function mapData($oldRecord): array
    {
        return [
            'id' => $oldRecord->id,
            'name' => $oldRecord->project_name,
            'description' => $oldRecord->project_description,
            'start_date' => $this->parseDate($oldRecord->start_date),
            'expected_end_date' => $this->parseDate($oldRecord->end_date),
            'estimated_cost' => $oldRecord->estimated_cost,
            'total_cost' => $oldRecord->total_cost,
            'status' => $this->mapStatus($oldRecord->status),
            'order_id' => $oldRecord->linked_request_id,
            'initiative_project_id' => $oldRecord->initiative_project_id,
            'created_at' => $this->parseDateTime($oldRecord->created_at),
            'updated_at' => $this->parseDateTime($oldRecord->modified_at ?: $oldRecord->created_at),
            'created_by' => $oldRecord->created_by,

            // Additional data for activity logs
            'old_record' => $oldRecord,
        ];
    }

    protected function validateData(array $data): bool
    {
        // Check if initiative project exists
        if (! InitiativeProject::find($data['initiative_project_id'])) {
            $this->warn("⚠️  Initiative project with ID {$data['initiative_project_id']} does not exist");

            return false;
        }

        // Check if order exists (if provided)
        if (! empty($data['order_id']) && ! Order::find($data['order_id'])) {
            $this->warn("⚠️  Order with ID {$data['order_id']} does not exist");

            return false;
        }

        // Check if created_by user exists
        if (! empty($data['created_by']) && ! User::find($data['created_by'])) {
            $this->warn("⚠️  User with ID {$data['created_by']} does not exist");

            return false;
        }

        // Check if charter already exists
        $exists = DB::table('project_charters')
            ->where('id', $data['id'])
            ->exists();

        if ($exists) {
            $this->warn("⚠️  Project charter with ID {$data['id']} already exists");

            return false;
        }

        // Validate dates
        if ($data['start_date'] && $data['expected_end_date'] && $data['start_date'] > $data['expected_end_date']) {
            $this->warn("⚠️  Start date is after expected end date for charter ID {$data['id']}");

            return false;
        }

        return true;
    }

    private function createActivityLogs(ProjectCharter $charter, object $oldRecord, array $data): void
    {
        $activities = $this->generateActivityLogs($charter, $oldRecord, $data);
        $createdActivitiesCount = 0;

        foreach ($activities as $activityData) {
            if (empty($activityData['causer_id']) || empty($activityData['created_at'])) {
                continue;
            }

            $causer = User::find($activityData['causer_id']);
            if (! $causer) {
                continue;
            }

            // Store the original timestamp temporarily
            $originalTimestamp = $activityData['created_at'];

            // Create activity log using the same pattern as ProjectCharter model
            $activity = activity('project_charter')
                ->performedOn($charter)
                ->causedBy($causer)
                ->event($activityData['event'])
                ->withProperties($activityData['properties'])
                ->log($activityData['description']);

            // Update the created_at timestamp to match the original datetime
            DB::table('activity_log')
                ->where('subject_type', 'App\\Models\\ProjectCharter')
                ->where('subject_id', $charter->getKey())
                ->where('description', $activityData['description'])
                ->where('event', $activityData['event'])
                ->where('causer_id', $activityData['causer_id'])
                ->orderBy('created_at', 'desc')
                ->limit(1)
                ->update([
                    'created_at' => $originalTimestamp,
                    'updated_at' => $originalTimestamp,
                ]);

            $createdActivitiesCount++;
        }

        if ($createdActivitiesCount > 0) {
            $this->info("📋 Created {$createdActivitiesCount} activity logs for project charter {$charter->getKey()}");
        }
    }

    private function generateActivityLogs(ProjectCharter $charter, object $oldRecord, array $data): array
    {
        $activities = [];

        // Add the "created" event as the first activity log
        $activities[] = [
            'description' => 'created',
            'causer_id' => $data['created_by'],
            'properties' => [
                'attributes' => $charter->toArray(),
            ],
            'event' => 'created',
            'created_at' => $data['created_at'],
        ];

        // Handle approval flow based on old status and approval data
        if (! empty($oldRecord->approved_at) && ! empty($oldRecord->approved_by)) {
            // If status is APPROVED and we have approval data, create approval activity
            if ($oldRecord->status === 'APPROVED') {
                $activities[] = [
                    'description' => 'Charter approved',
                    'causer_id' => $oldRecord->approved_by,
                    'properties' => [
                        'old_status' => ProjectCharter::STATUS_AWAITING_APPROVAL,
                        'new_status' => ProjectCharter::STATUS_APPROVED,
                        'notes' => 'Migrated approval from legacy system',
                    ],
                    'event' => 'approved',
                    'created_at' => $this->parseDateTime($oldRecord->approved_at),
                ];
            }
        }

        // Handle submission for approval if status requires it
        if (in_array($oldRecord->status, ['AWAITING_OPERATIONAL_MANAGER_APPROVAL', 'APPROVED', 'REJECTED'])) {
            // Add submission for approval activity before approval/rejection
            $submissionTime = $this->parseDateTime($oldRecord->approved_at) ?? $data['created_at'];
            // Subtract a few minutes to show submission happened before approval
            if ($submissionTime) {
                $submissionTime = $submissionTime->copy()->subMinutes(5);
            }

            $activities[] = [
                'description' => 'Charter submitted for approval',
                'causer_id' => $data['created_by'],
                'properties' => [
                    'old_status' => ProjectCharter::STATUS_DRAFT,
                    'new_status' => ProjectCharter::STATUS_AWAITING_APPROVAL,
                    'notes' => 'Migrated submission from legacy system',
                ],
                'event' => 'submitted_for_approval',
                'created_at' => $submissionTime,
            ];
        }

        return $activities;
    }

    private function mapStatus(string $oldStatus): string
    {
        $statusMap = [
            'DRAFT' => ProjectCharter::STATUS_DRAFT,
            'AWAITING_OPERATIONAL_MANAGER_APPROVAL' => ProjectCharter::STATUS_AWAITING_APPROVAL,
            'APPROVED' => ProjectCharter::STATUS_APPROVED,
            'REJECTED' => ProjectCharter::STATUS_REJECTED,
        ];

        $mappedStatus = $statusMap[$oldStatus] ?? ProjectCharter::STATUS_DRAFT;

        // Log the mapping for debugging
        if (! isset($statusMap[$oldStatus]) && ! empty($oldStatus)) {
            $this->warn("⚠️  Unknown status '{$oldStatus}' mapped to DRAFT");
        }

        return $mappedStatus;
    }

    protected function parseDate($date): ?Carbon
    {
        if (empty($date)) {
            return null;
        }

        try {
            return Carbon::parse($date)->startOfDay();
        } catch (\Exception $e) {
            return null;
        }
    }

    protected function parseDateTime($dateTime): ?Carbon
    {
        if (empty($dateTime)) {
            return null;
        }

        try {
            return Carbon::parse($dateTime);
        } catch (\Exception $e) {
            return null;
        }
    }

    protected function getStatsSummary(): array
    {
        return [
            'Project-charters' => [
                'Total' => $this->stats['total'] ?? 0,
                'Migrated' => $this->stats['migrated'] ?? 0,
                'Skipped' => $this->stats['skipped'] ?? 0,
                'Errors' => $this->stats['errors'] ?? 0,
            ],
        ];
    }
}
