<?php

namespace App\Services\Import\Importers;

use App\Services\Import\Contracts\ImporterInterface;

// PRC-707 — Jenerik CSV importer. MVP kapsamı: müşteri (clients) importu tam.
// Diğer entity'ler (services/domains/invoices) alan iskeleti tanımlı ama
// normalize/persist follow-up'ta genişletilecek (residual).
//
// Güvenlik: dosya yolu ImportService tarafından storage içinde güvenli
// (path-traversal'a kapalı) verilir; burada yalnız fopen + fgetcsv.
class CsvImporter implements ImporterInterface
{
    public const MAX_ROWS = 50000;

    public function key(): string
    {
        return 'csv';
    }

    public function supportedEntities(): array
    {
        return [
            'clients' => [
                'required' => ['email', 'first_name'],
                'optional' => [
                    'last_name', 'company_name', 'phone', 'address1', 'address2',
                    'city', 'state', 'postcode', 'country_code', 'tax_id',
                    'password_hash', 'external_id', 'status',
                ],
            ],
            // İskelet — MVP'de normalize edilmiyor (residual: follow-up ticket).
            'services' => ['required' => ['client_email', 'product'], 'optional' => ['domain', 'status', 'next_due_date', 'amount']],
            'domains' => ['required' => ['client_email', 'domain'], 'optional' => ['status', 'expire_date', 'registrar']],
            'invoices' => ['required' => ['client_email', 'total'], 'optional' => ['status', 'date', 'due_date', 'external_id']],
        ];
    }

    public function analyze(string $entity, array $source): array
    {
        $path = $source['path'] ?? null;
        if (! $path || ! is_readable($path)) {
            return ['headers' => [], 'sample' => [], 'error' => 'CSV okunamadı.'];
        }

        $handle = fopen($path, 'r');
        if (! $handle) {
            return ['headers' => [], 'sample' => [], 'error' => 'CSV açılamadı.'];
        }

        $headers = fgetcsv($handle) ?: [];
        $headers = array_map(fn ($h) => trim((string) $h), $headers);

        $sample = [];
        while (count($sample) < 5 && ($row = fgetcsv($handle)) !== false) {
            $assoc = [];
            foreach ($headers as $i => $h) {
                $assoc[$h] = trim((string) ($row[$i] ?? ''));
            }
            $sample[] = $assoc;
        }
        fclose($handle);

        return ['headers' => $headers, 'sample' => $sample];
    }

    public function rows(string $entity, array $source, array $mapping, array $options): iterable
    {
        $path = $source['path'] ?? null;
        if (! $path || ! is_readable($path)) {
            return;
        }

        $handle = fopen($path, 'r');
        if (! $handle) {
            return;
        }

        $headers = fgetcsv($handle) ?: [];
        $headers = array_map(fn ($h) => mb_strtolower(trim((string) $h)), $headers);
        $index = $this->buildColumnIndex($headers, $mapping);

        $count = 0;
        while (($raw = fgetcsv($handle)) !== false) {
            if ($count++ >= self::MAX_ROWS) {
                yield ['external_ref' => '', 'data' => [], 'error' => 'Satır limiti aşıldı: '.self::MAX_ROWS];
                break;
            }

            // Tamamen boş satır → atla.
            if (count(array_filter($raw, fn ($c) => trim((string) $c) !== '')) === 0) {
                continue;
            }

            $data = [];
            foreach ($index as $field => $pos) {
                $data[$field] = trim((string) ($raw[$pos] ?? ''));
            }

            // external_ref: idempotency anahtarı — external_id varsa o, yoksa email.
            $externalRef = $data['external_id'] ?? '';
            if ($externalRef === '') {
                $externalRef = mb_strtolower($data['email'] ?? '');
            }

            yield ['external_ref' => $externalRef, 'data' => $data];
        }
        fclose($handle);
    }

    /** field → sütun index (eşlenen başlık adından, case-insensitive). */
    private function buildColumnIndex(array $normalizedHeaders, array $mapping): array
    {
        $index = [];
        foreach ($mapping as $field => $headerName) {
            if (! $headerName) {
                continue;
            }
            $pos = array_search(mb_strtolower(trim((string) $headerName)), $normalizedHeaders, true);
            if ($pos !== false) {
                $index[$field] = $pos;
            }
        }

        return $index;
    }
}
