<?php

namespace App\Console\Commands\Migrations;

use Carbon\Carbon;
use Illuminate\Console\Command;

abstract class BaseMigration
{
    protected Command $command;

    protected string $connection;

    protected array $stats = [
        'total' => 0,
        'migrated' => 0,
        'skipped' => 0,
        'errors' => 0,
    ];

    public function __construct(Command $command, string $connection)
    {
        $this->command = $command;
        $this->connection = $connection;
    }

    /**
     * Get the migration statistics
     */
    public function getStats(): array
    {
        return $this->stats;
    }

    /**
     * Reset migration statistics
     */
    public function resetStats(): void
    {
        $this->stats = [
            'total' => 0,
            'migrated' => 0,
            'skipped' => 0,
            'errors' => 0,
        ];
    }

    /**
     * Execute the migration
     */
    abstract public function migrate(bool $dryRun, int $batchSize, int $startFrom): void;

    /**
     * Get the model name for display purposes
     */
    abstract protected function getModelName(): string;

    /**
     * Get the model class name
     */
    abstract protected function getModelClass(): string;

    /**
     * Map old data to new schema
     */
    abstract protected function mapData(object $oldRecord): array;

    /**
     * Validate mapped data
     */
    abstract protected function validateData(array $data): bool;

    /**
     * Get additional validation rules specific to this model
     */
    protected function getValidationRules(): array
    {
        return [];
    }

    /**
     * Parse datetime from various formats
     */
    protected function parseDateTime($datetime): ?Carbon
    {
        if (empty($datetime)) {
            return null;
        }

        try {
            return Carbon::parse($datetime);
        } catch (\Exception $e) {
            return now();
        }
    }

    /**
     * Parse date from various formats
     */
    protected function parseDate($date): ?Carbon
    {
        if (empty($date)) {
            return null;
        }

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

    /**
     * Parse coordinates from string format like "24.75099448167933,46.82626031787359"
     */
    protected function parseCoordinates(?string $coordinates): array
    {
        if (empty($coordinates)) {
            return ['lat' => null, 'lng' => null];
        }

        try {
            // Handle various coordinate formats
            $coords = explode(',', $coordinates);
            if (count($coords) >= 2) {
                $lat = (float) trim($coords[0]);
                $lng = (float) trim($coords[1]);

                // Validate coordinate ranges (rough validation for Saudi Arabia region)
                if ($lat >= 16 && $lat <= 33 && $lng >= 34 && $lng <= 56) {
                    return ['lat' => $lat, 'lng' => $lng];
                }
            }
        } catch (\Exception $e) {
            $this->command->warn("⚠️  Invalid coordinates format: {$coordinates}");
        }

        return ['lat' => null, 'lng' => null];
    }

    /**
     * Create a model instance with unguarded mass assignment
     */
    protected function createModel(array $data): void
    {
        $modelClass = $this->getModelClass();
        $modelClass::unguarded(function () use ($data, $modelClass) {
            $modelClass::create($data);
        });
    }

    /**
     * Check if a record with the given ID already exists
     */
    protected function recordExists(int $id): bool
    {
        $modelClass = $this->getModelClass();

        return $modelClass::find($id) !== null;
    }

    /**
     * Log informational message
     */
    protected function info(string $message): void
    {
        $this->command->info($message);
    }

    /**
     * Log warning message
     */
    protected function warn(string $message): void
    {
        $this->command->warn($message);
    }

    /**
     * Log error message
     */
    protected function error(string $message): void
    {
        $this->command->error($message);
    }
}
