<?php

namespace App\Services;

use App\Models\VisitRawStaging;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;

class ImportValidator
{
    /** Expected column aliases (Excel header variations) */
    protected array $columnMap = [
        'mr' => ['mr', 'mr_name', 'medical_representative', 'rep_name'],
        'date' => ['date', 'visit_date', 'date_of_visit', 'dt'],
        'doctor' => ['doctor', 'doctor_name', 'dr', 'doctor_name'],
        'clinic' => ['clinic', 'clinic_name', 'hospital', 'location'],
        'lat' => ['lat', 'latitude', 'latitud', 'gps_lat'],
        'lng' => ['lng', 'longitude', 'long', 'lngitude', 'gps_lng'],
        'specialty' => ['specialty', 'speciality', 'spec'],
    ];

    public function validateStagingBatch(int $importBatchId): array
    {
        $rows = VisitRawStaging::where('import_batch_id', $importBatchId)->get();
        $stats = [
            'total' => $rows->count(),
            'valid' => 0,
            'invalid' => 0,
            'partial' => 0,
            'errors' => [],
        ];

        foreach ($rows as $row) {
            $result = $this->validateRow($row->raw_data);
            $row->update([
                'validation_status' => $result['status'],
                'validation_errors' => $result['errors'] ?? null,
            ]);

            $stats[$result['status']]++;

            if (! empty($result['errors'])) {
                $stats['errors'][] = [
                    'row' => $row->row_index,
                    'errors' => $result['errors'],
                ];
            }
        }

        return $stats;
    }

    public function validateRow(array $rawData): array
    {
        $errors = [];
        $normalized = $this->normalizeRow($rawData);

        // Required: at least MR or doctor for mapping
        $hasMr = ! empty($normalized['mr']);
        $hasDoctor = ! empty($normalized['doctor']);
        if (! $hasMr && ! $hasDoctor) {
            $errors[] = 'Missing MR name and Doctor name (at least one required)';
        }

        // Date validation and normalization
        if (! empty($rawData['date'] ?? $rawData['visit_date'] ?? null)) {
            $parsed = $this->parseDate($rawData['date'] ?? $rawData['visit_date'] ?? null);
            if (! $parsed) {
                $errors[] = 'Invalid date format';
            }
        }

        // GPS if present should be numeric
        if (isset($normalized['lat']) && ! is_numeric($normalized['lat'])) {
            $errors[] = 'Invalid latitude';
        }
        if (isset($normalized['lng']) && ! is_numeric($normalized['lng'])) {
            $errors[] = 'Invalid longitude';
        }

        $status = empty($errors) ? 'valid' : (($hasMr || $hasDoctor) ? 'partial' : 'invalid');

        return [
            'status' => $status,
            'errors' => $errors ?: null,
            'normalized' => $normalized,
        ];
    }

    public function normalizeRow(array $rawData): array
    {
        $out = [];
        foreach ($this->columnMap as $key => $aliases) {
            foreach ($aliases as $alias) {
                $found = $rawData[$alias] ?? $rawData[ucfirst($alias)] ?? $rawData[strtolower($alias)] ?? null;
                if ($found !== null && $found !== '') {
                    $out[$key] = is_string($found) ? trim($found) : $found;
                    break;
                }
            }
        }
        return $out;
    }

    public function parseDate(mixed $value): ?string
    {
        if ($value instanceof \DateTimeInterface) {
            return $value->format('Y-m-d');
        }
        try {
            return Carbon::parse($value)->format('Y-m-d');
        } catch (\Throwable $e) {
            return null;
        }
    }
}
