<?php

namespace App\Console\Commands\Migrations;

use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Spatie\Permission\Models\Role;

class UserMigration extends BaseMigration
{
    /**
     * Default password for migrated users
     */
    protected string $defaultPassword = 'TempPassword@123';

    /**
     * Role mapping from old English names to new Arabic names
     */
    protected array $roleMapping = [
        'ASSOCIATION_USER' => 'مدير جمعية',
        'PLANNING_ADMIN' => 'مدير التخطيط',
        'OPERATION_ADMIN' => 'مدير مشروع',
        'OPERATIONAL_MANGER' => 'مدير إدارة المشاريع',
        'CLASSIFICATION_ADMIN' => 'مدير التصنيف',
        'ACCOUNTANT_ADMIN' => 'المحاسب',
        'FINANCIAL_AUDITOR_ADMIN' => 'مراجع الحسابات',
        'SHARED_SERVICES_ADMIN' => 'مدير الخدمات المشتركة',
        'CHIEF_EXECUTIVE_OFFICER' => 'الرئيس التنفيذي',
    ];

    /**
     * Execute the user migration
     */
    public function migrate(bool $dryRun, int $batchSize, int $startFrom): void
    {
        $this->info('👤 Starting users migration...');

        $oldDb = DB::connection($this->connection);

        // Get total count
        $totalCount = $oldDb->table('sek_users')->count();
        $this->stats['total'] = $totalCount;

        $this->info("📊 Found {$totalCount} users to migrate");

        if ($totalCount === 0) {
            $this->warn('⚠️  No users found to migrate');

            return;
        }

        // Process in batches
        $processed = 0;
        $bar = $this->command->getOutput()->createProgressBar($totalCount);

        $oldDb->table('sek_users')
            ->orderBy('id')
            ->skip($startFrom)
            ->chunk($batchSize, function ($oldUsers) use ($dryRun, &$processed, $bar) {
                foreach ($oldUsers as $oldUser) {
                    try {
                        $mappedData = $this->mapData($oldUser);

                        if ($this->validateData($mappedData)) {
                            if (! $dryRun) {
                                // Check if user with this ID already exists
                                if ($this->recordExists($mappedData['id'])) {
                                    $this->warn("⚠️  User with ID {$mappedData['id']} already exists, skipping");
                                    $this->stats['skipped']++;
                                } else {
                                    // Create user
                                    $user = $this->createModelAndReturn($mappedData);

                                    // Assign role if specified
                                    $this->assignUserRole($user, $oldUser);

                                    $this->stats['migrated']++;
                                }
                            } else {
                                $this->stats['migrated']++;
                            }
                        } else {
                            $this->stats['skipped']++;
                            $this->warn("⚠️  Skipped user ID {$oldUser->id}: validation failed");
                        }
                    } catch (\Exception $e) {
                        $this->stats['errors']++;
                        $this->error("❌ Error migrating user ID {$oldUser->id}: ".$e->getMessage());
                    }

                    $processed++;
                    $bar->advance();
                }
            });

        $bar->finish();
        $this->command->newLine();
        $this->info('✅ Users migration completed');
    }

    /**
     * Get the model name for display purposes
     */
    protected function getModelName(): string
    {
        return 'User';
    }

    /**
     * Get the model class name
     */
    protected function getModelClass(): string
    {
        return User::class;
    }

    /**
     * Map old user data to new schema
     */
    protected function mapData(object $oldUser): array
    {

        $fullName = $oldUser->first_name_ar ?? $oldUser->entered_association_owner_fullname;

        $data = [
            'id' => $oldUser->id, // Preserve original ID
            'name' => $fullName ?? "User {$oldUser->id}",
            'email' => $this->generateEmailIfMissing($oldUser),
            'phone_number' => $oldUser->mobile_number,
            'password' => Hash::make($this->defaultPassword),
            'association_id' => $oldUser->association_id,
            'accepted_terms_and_conditions_at' => ($oldUser->is_term_accepted ?? false) ? $this->parseDateTime($oldUser->created_at) : null,
            'created_at' => $this->parseDateTime($oldUser->created_at),
            'updated_at' => $this->parseDateTime($oldUser->modified_at ?? $oldUser->created_at),
        ];

        // Set email verification if it was verified in old system
        if (! empty($oldUser->email_is_verified) && $oldUser->email_is_verified == 1) {
            $data['email_verified_at'] = $data['created_at'];
        }

        // Log information about fields we're not migrating
        $this->logSkippedUserFields($oldUser);

        return array_filter($data); // Remove null values
    }

    /**
     * Validate user data
     */
    protected function validateData(array $data): bool
    {
        $validator = Validator::make($data, [
            'id' => 'required|integer|min:1',
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users,email',
            'phone_number' => 'nullable|string|max:20',
            'password' => 'required|string',
            'accepted_terms_and_conditions_at' => 'nullable|date',
        ]);

        if ($validator->fails()) {
            $this->error('Validation errors: '.implode(', ', $validator->errors()->all()));

            return false;
        }

        // Skip users without email or phone
        if (empty($data['email']) && empty($data['phone_number'])) {
            $this->warn('Skipping user without email or phone number');

            return false;
        }

        return true;
    }

    /**
     * Log fields from old user that we're not migrating
     */
    protected function logSkippedUserFields(object $oldUser): void
    {
        $skippedFields = [
            'position_at_association',
            'is_association_admin',
            'entered_association_owner_fullname',
            'license_expiration_date',
            'entered_association_name_ar',
            'entered_association_name_en',
            'gender',
            'date_of_birth_gregorian',
            'mobile_number_is_verified',
            'lang',
            'role',
            'association_admin_verified_by',
            'association_admin_verified_at',
            'user_photo',
            'is_profile_edit_locked',
            'profile_locked_once',
            'is_user_locked',
            'geolocation_update_status',
        ];

        $hasData = [];
        foreach ($skippedFields as $field) {
            if (! empty($oldUser->$field)) {
                $hasData[] = $field;
            }
        }

        if (! empty($hasData)) {
            $this->info("📝 User {$oldUser->id} has data in skipped fields: ".implode(', ', $hasData));
        }
    }

    /**
     * Get the default password used for migrated users
     */
    public function getDefaultPassword(): string
    {
        return $this->defaultPassword;
    }

    /**
     * Create a model and return the instance
     */
    protected function createModelAndReturn(array $data): User
    {
        $user = null;
        User::unguarded(function () use ($data, &$user) {
            $user = User::create($data);
        });

        return $user ?? throw new \Exception('Failed to create user');
    }

    /**
     * Generate an email for users without one
     */
    private function generateEmailIfMissing(object $oldUser): string
    {
        // If email exists, use it
        if (! empty($oldUser->email)) {
            return $oldUser->email;
        }

        // Generate a placeholder email based on user ID and phone if available
        if (! empty($oldUser->mobile_number)) {
            return "user{$oldUser->id}.{$oldUser->mobile_number}@migration.placeholder";
        }

        // Fallback to just user ID
        return "user{$oldUser->id}@migration.placeholder";
    }

    /**
     * Assign role to user based on old data
     */
    protected function assignUserRole(User $user, object $oldUser): void
    {
        if (! empty($oldUser->role)) {
            try {
                // Map old English role name to new Arabic role name
                $newRoleName = $this->roleMapping[$oldUser->role] ?? null;

                if (! $newRoleName) {
                    $this->warn("⚠️  Unknown role '{$oldUser->role}' for user {$user->getKey()}, skipping role assignment");

                    return;
                }

                // Check if role exists
                $role = Role::where('name', $newRoleName)->first();
                if ($role) {
                    $user->assignRole($newRoleName);
                    $this->info("📝 Assigned role '{$newRoleName}' (was '{$oldUser->role}') to user {$user->getKey()}");
                } else {
                    $this->warn("⚠️  Role '{$newRoleName}' not found for user {$user->getKey()}");
                }
            } catch (\Exception $e) {
                $this->warn("⚠️  Failed to assign role '{$oldUser->role}' to user {$user->getKey()}: ".$e->getMessage());
            }
        }
    }
}
