<?php

namespace App\Services;

use App\Models\Tenant\Client;
use App\Models\Tenant\Vehicle;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\StreamedResponse;

/**
 * Plain-CSV import/export for the most-imported entities (Clients, Vehicles).
 * No external package — uses fputcsv / fgetcsv with explicit BOM for Excel UTF-8.
 */
class CsvImportExport
{
    public const CLIENT_COLUMNS = [
        'name', 'phone', 'phone_alt', 'email', 'company_name',
        'type', 'status', 'source', 'marketing_channel',
        'discount_pct', 'balance', 'notes',
    ];

    public const VEHICLE_COLUMNS = [
        'plate', 'vin', 'brand', 'model', 'year',
        'engine', 'gearbox', 'fuel', 'mileage',
        'color', 'notes', 'client_phone',
    ];

    public function exportClients(): StreamedResponse
    {
        return $this->stream('clienti-' . date('Y-m-d') . '.csv', self::CLIENT_COLUMNS, function ($out) {
            Client::orderBy('name')->chunk(500, function ($rows) use ($out) {
                foreach ($rows as $row) {
                    fputcsv($out, [
                        $row->name, $row->phone, $row->phone_alt, $row->email, $row->company_name,
                        $row->type, $row->status, $row->source, $row->marketing_channel,
                        $row->discount_pct, $row->balance, $row->notes,
                    ]);
                }
            });
        });
    }

    public function exportVehicles(): StreamedResponse
    {
        return $this->stream('automobile-' . date('Y-m-d') . '.csv', self::VEHICLE_COLUMNS, function ($out) {
            Vehicle::with('client:id,phone')->orderBy('plate')->chunk(500, function ($rows) use ($out) {
                foreach ($rows as $row) {
                    fputcsv($out, [
                        $row->plate, $row->vin, $row->make, $row->model, $row->year,
                        $row->engine, $row->gearbox, $row->fuel, $row->mileage,
                        $row->color, $row->notes, $row->client?->phone,
                    ]);
                }
            });
        });
    }

    /**
     * Import clients from CSV. Returns ['imported' => N, 'skipped' => M, 'errors' => [...]].
     */
    public function importClients(string $absolutePath): array
    {
        return $this->import($absolutePath, self::CLIENT_COLUMNS, function (array $row) {
            $phone = $row['phone'] ?? null;
            if (empty($phone) || empty($row['name'])) {
                return ['skip', 'phone & name required'];
            }
            $existing = Client::where('phone', $phone)->first();
            if ($existing) {
                return ['skip', 'phone already exists'];
            }
            Client::create([
                'name' => $row['name'],
                'phone' => $phone,
                'phone_alt' => $row['phone_alt'] ?? null,
                'email' => $row['email'] ?? null,
                'company_name' => $row['company_name'] ?? null,
                'type' => $row['type'] ?? 'individual',
                'status' => $row['status'] ?? 'active',
                'source' => $row['source'] ?? null,
                'marketing_channel' => $row['marketing_channel'] ?? null,
                'discount_pct' => (float) ($row['discount_pct'] ?? 0),
                'balance' => (float) ($row['balance'] ?? 0),
                'notes' => $row['notes'] ?? null,
            ]);
            return ['ok', null];
        });
    }

    public function importVehicles(string $absolutePath): array
    {
        return $this->import($absolutePath, self::VEHICLE_COLUMNS, function (array $row) {
            if (empty($row['plate'])) {
                return ['skip', 'plate required'];
            }
            $client = null;
            if (! empty($row['client_phone'])) {
                $client = Client::where('phone', $row['client_phone'])->first();
            }
            if (! $client) {
                return ['skip', 'client_phone not found'];
            }
            if (Vehicle::where('plate', $row['plate'])->exists()) {
                return ['skip', 'plate already exists'];
            }
            Vehicle::create([
                'client_id' => $client->id,
                'plate' => $row['plate'],
                'vin' => $row['vin'] ?? null,
                // CSV header keeps the user-friendly "brand" name, but the column is `make`.
                'make' => $row['brand'] ?? null,
                'model' => $row['model'] ?? null,
                'year' => (int) ($row['year'] ?? 0) ?: null,
                'engine' => $row['engine'] ?? null,
                'gearbox' => $row['gearbox'] ?? null,
                'fuel' => $row['fuel'] ?? null,
                'mileage' => (int) ($row['mileage'] ?? 0) ?: null,
                'color' => $row['color'] ?? null,
                'notes' => $row['notes'] ?? null,
            ]);
            return ['ok', null];
        });
    }

    private function stream(string $filename, array $columns, \Closure $writer): StreamedResponse
    {
        return response()->streamDownload(function () use ($columns, $writer) {
            $out = fopen('php://output', 'w');
            // UTF-8 BOM so Excel opens with correct diacritics.
            fwrite($out, "\xEF\xBB\xBF");
            fputcsv($out, $columns);
            $writer($out);
            fclose($out);
        }, $filename, ['Content-Type' => 'text/csv; charset=utf-8']);
    }

    private function import(string $absolutePath, array $columns, \Closure $rowHandler): array
    {
        if (! file_exists($absolutePath)) {
            return ['imported' => 0, 'skipped' => 0, 'errors' => ['file not found']];
        }
        $h = fopen($absolutePath, 'r');
        // Strip UTF-8 BOM if present.
        $bom = fread($h, 3);
        if ($bom !== "\xEF\xBB\xBF") {
            rewind($h);
        }
        $header = fgetcsv($h);
        if (! $header) {
            fclose($h);
            return ['imported' => 0, 'skipped' => 0, 'errors' => ['empty file']];
        }
        $header = array_map('trim', $header);
        $imported = 0;
        $skipped = 0;
        $errors = [];
        $line = 1;
        DB::beginTransaction();
        try {
            while (($cells = fgetcsv($h)) !== false) {
                $line++;
                if (count($cells) !== count($header)) {
                    $errors[] = "L{$line}: column count mismatch";
                    $skipped++;
                    continue;
                }
                $row = array_combine($header, array_map(fn ($c) => $c === '' ? null : $c, $cells));
                [$status, $err] = $rowHandler($row);
                if ($status === 'ok') {
                    $imported++;
                } else {
                    $skipped++;
                    if ($err) $errors[] = "L{$line}: {$err}";
                }
            }
            DB::commit();
        } catch (\Throwable $e) {
            DB::rollBack();
            $errors[] = 'fatal: ' . $e->getMessage();
        }
        fclose($h);
        return ['imported' => $imported, 'skipped' => $skipped, 'errors' => array_slice($errors, 0, 50)];
    }
}
