<?php

namespace App\Http\Controllers\Api\Admin;

use App\Http\Controllers\Controller;
use App\Models\ConsultantProfile;
use App\Models\Listing;
use App\Models\ListingCategory;
use App\Models\ListingMedia;
use App\Services\ListingFeatureService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
use SimpleXMLElement;
use XMLWriter;

/**
 * İlanların XML ile dışa/içe aktarımı (admin "İşlemler" sayfası).
 *
 * Şema (v1, slug = upsert anahtarı):
 *   <pella-listings version="1">
 *     <listing>
 *       <slug>..</slug>
 *       <title lang="tr">..</title><title lang="en">..</title>   (short_description/description aynı)
 *       <category>villa</category>                (kategori slug)
 *       <consultant>pella-global-realty</consultant> (danışman slug; yoksa içe aktaran kullanıcı)
 *       <status>published</status> <price currency="EUR">..</price> <is_featured>true</is_featured>
 *       <location><country/><city/><district/><neighborhood/><address/><latitude/><longitude/></location>
 *       <area gross=".." net=".."/>
 *       <features><feature key="pool">true</feature>
 *                 <feature key="property_view"><value>Sea</value><value>City</value></feature></features>
 *       <media><image cover="true" order="1">https://..</image></media>
 *     </listing>
 *   </pella-listings>
 */
class ListingTransferController extends Controller
{
    private const LOCALES = ['tr', 'en'];
    private const TRANSLATABLE = ['title', 'short_description', 'description'];

    public function __construct(private ListingFeatureService $features)
    {
    }

    /* ------------------------------ EXPORT ------------------------------ */

    public function export()
    {
        $listings = Listing::query()
            ->with(['category', 'consultantProfile', 'media', 'featureValues.feature'])
            ->orderBy('id')
            ->get();

        $xml = new XMLWriter();
        $xml->openMemory();
        $xml->setIndent(true);
        $xml->setIndentString('  ');
        $xml->startDocument('1.0', 'UTF-8');
        $xml->startElement('pella-listings');
        $xml->writeAttribute('version', '1');
        $xml->writeAttribute('exported_at', now()->toISOString());
        $xml->writeAttribute('count', (string) $listings->count());

        foreach ($listings as $listing) {
            $xml->startElement('listing');
            $xml->writeElement('slug', $listing->slug);

            // Çok dilli alanlar: her locale ayrı elemanda.
            foreach (self::TRANSLATABLE as $field) {
                foreach ($listing->getTranslations($field) as $lang => $value) {
                    if ($value === null || $value === '') continue;
                    $xml->startElement($field);
                    $xml->writeAttribute('lang', $lang);
                    $xml->text($value);
                    $xml->endElement();
                }
            }

            $xml->writeElement('category', $listing->category?->slug ?? '');
            $xml->writeElement('consultant', $listing->consultantProfile?->slug ?? '');
            $xml->writeElement('status', $listing->status);

            $xml->startElement('price');
            $xml->writeAttribute('currency', $listing->currency ?? 'EUR');
            $xml->text((string) ($listing->price ?? ''));
            $xml->endElement();

            $xml->writeElement('is_featured', $listing->is_featured ? 'true' : 'false');
            if ($listing->published_at) {
                $xml->writeElement('published_at', $listing->published_at->toISOString());
            }

            $xml->startElement('location');
            foreach (['country', 'city', 'district', 'neighborhood', 'address', 'latitude', 'longitude'] as $col) {
                $xml->writeElement($col, (string) ($listing->{$col} ?? ''));
            }
            $xml->endElement();

            $xml->startElement('area');
            $xml->writeAttribute('gross', (string) ($listing->gross_area ?? ''));
            $xml->writeAttribute('net', (string) ($listing->net_area ?? ''));
            $xml->endElement();

            $xml->startElement('features');
            foreach ($listing->featureValues as $fv) {
                if (! $fv->feature) continue;
                $xml->startElement('feature');
                $xml->writeAttribute('key', $fv->feature->key);
                if ($fv->value_json !== null) {
                    foreach ((array) $fv->value_json as $item) {
                        $xml->writeElement('value', (string) $item);
                    }
                } elseif ($fv->value_boolean !== null) {
                    $xml->text($fv->value_boolean ? 'true' : 'false');
                } elseif ($fv->value_number !== null) {
                    $xml->text((string) $fv->value_number);
                } else {
                    $xml->text((string) ($fv->value_text ?? ''));
                }
                $xml->endElement();
            }
            $xml->endElement();

            $xml->startElement('media');
            foreach ($listing->media as $media) {
                $url = $media->file_url ?? $media->file_path;
                if (! $url) continue;
                $xml->startElement('image');
                $xml->writeAttribute('cover', $media->is_cover ? 'true' : 'false');
                $xml->writeAttribute('order', (string) ($media->sort_order ?? 0));
                if ($media->alt_text) {
                    $xml->writeAttribute('alt', $media->alt_text);
                }
                $xml->text($url);
                $xml->endElement();
            }
            $xml->endElement();

            $xml->endElement(); // listing
        }

        $xml->endElement(); // pella-listings
        $xml->endDocument();

        $filename = 'pella-listings-' . now()->format('Y-m-d-His') . '.xml';

        return response($xml->outputMemory(), 200, [
            'Content-Type' => 'application/xml; charset=UTF-8',
            'Content-Disposition' => "attachment; filename=\"{$filename}\"",
        ]);
    }

    /* ------------------------------ IMPORT ------------------------------ */

    public function import(Request $request)
    {
        $request->validate([
            'file' => ['required', 'file', 'max:10240'], // 10MB
        ]);

        $raw = file_get_contents($request->file('file')->getRealPath());

        libxml_use_internal_errors(true);
        // LIBXML_NONET: dış kaynak yükleme kapalı (XXE koruması).
        $doc = simplexml_load_string($raw, SimpleXMLElement::class, LIBXML_NONET);
        if ($doc === false || $doc->getName() !== 'pella-listings') {
            return response()->json([
                'message' => 'Geçersiz XML: kök eleman <pella-listings> olmalı.',
            ], 422);
        }

        $categories = ListingCategory::pluck('id', 'slug');
        $consultants = ConsultantProfile::pluck('id', 'slug');
        $fallbackConsultantId = $request->user()->consultantProfile?->id;

        $created = 0;
        $updated = 0;
        $errors = [];

        foreach ($doc->listing as $index => $node) {
            $slug = trim((string) $node->slug);
            $label = $slug !== '' ? $slug : "#" . ((int) $index + 1);

            try {
                if ($slug === '') {
                    throw new \RuntimeException('slug zorunludur.');
                }

                $categorySlug = trim((string) $node->category);
                $categoryId = $categories[$categorySlug] ?? null;
                if (! $categoryId) {
                    throw new \RuntimeException("Kategori bulunamadı: '{$categorySlug}'");
                }

                $consultantSlug = trim((string) $node->consultant);
                $consultantId = $consultants[$consultantSlug] ?? $fallbackConsultantId;
                if (! $consultantId) {
                    throw new \RuntimeException("Danışman bulunamadı: '{$consultantSlug}'");
                }

                // Çok dilli alanlar
                $translations = [];
                foreach (self::TRANSLATABLE as $field) {
                    foreach ($node->{$field} as $el) {
                        $lang = (string) ($el['lang'] ?? 'tr');
                        if (! in_array($lang, self::LOCALES, true)) continue;
                        $translations[$field][$lang] = (string) $el;
                    }
                }
                if (empty($translations['title'])) {
                    throw new \RuntimeException('En az bir dilde title zorunludur.');
                }

                $status = trim((string) $node->status) ?: 'pending';
                if (! in_array($status, ['draft', 'pending', 'published', 'rejected', 'archived'], true)) {
                    $status = 'pending';
                }

                // Feature'lar → ListingFeatureService::validate girdi formatı (key => value)
                $featureInput = [];
                if (isset($node->features)) {
                    foreach ($node->features->feature as $f) {
                        $key = trim((string) $f['key']);
                        if ($key === '') continue;
                        $values = [];
                        foreach ($f->value as $v) {
                            $values[] = (string) $v;
                        }
                        $featureInput[$key] = count($values) > 0 ? $values : (string) $f;
                    }
                }

                $num = fn (string $s) => is_numeric(trim($s)) ? trim($s) : null;

                DB::transaction(function () use (
                    $node, $slug, $categoryId, $consultantId, $translations,
                    $status, $featureInput, $num, &$created, &$updated
                ) {
                    $category = ListingCategory::findOrFail($categoryId);
                    $prepared = $this->features->validate($category, $featureInput);

                    $publishedAt = trim((string) $node->published_at);
                    $attributes = [
                        'consultant_profile_id' => $consultantId,
                        'category_id' => $categoryId,
                        'price' => $num((string) $node->price),
                        'currency' => trim((string) $node->price['currency']) ?: 'EUR',
                        'status' => $status,
                        'is_featured' => filter_var((string) $node->is_featured, FILTER_VALIDATE_BOOLEAN),
                        'country' => trim((string) $node->location->country) ?: null,
                        'city' => trim((string) $node->location->city) ?: null,
                        'district' => trim((string) $node->location->district) ?: null,
                        'neighborhood' => trim((string) $node->location->neighborhood) ?: null,
                        'address' => trim((string) $node->location->address) ?: null,
                        'latitude' => $num((string) $node->location->latitude),
                        'longitude' => $num((string) $node->location->longitude),
                        'gross_area' => $num((string) $node->area['gross']),
                        'net_area' => $num((string) $node->area['net']),
                        'published_at' => $status === 'published'
                            ? ($publishedAt !== '' ? $publishedAt : now())
                            : null,
                    ];

                    // Soft-delete: slug unique olduğundan çöpteki kayıt da eşleşmeli,
                    // yoksa aynı slug'la INSERT denenir ve unique index patlar.
                    $listing = Listing::withTrashed()->where('slug', $slug)->first();
                    if ($listing) {
                        $listing->fill($attributes);
                        $updated++;
                    } else {
                        $listing = new Listing($attributes + ['slug' => $slug, 'view_count' => 0]);
                        $created++;
                    }

                    foreach ($translations as $field => $byLang) {
                        $listing->setTranslations($field, $byLang);
                    }
                    $listing->save();

                    $this->features->sync($listing, $prepared);

                    // Medya: XML kaynak-doğrudur → mevcut set silinip yeniden yazılır.
                    if (isset($node->media)) {
                        $listing->media()->delete();
                        $order = 0;
                        $hasCover = false;
                        foreach ($node->media->image as $img) {
                            $url = trim((string) $img);
                            if ($url === '') continue;
                            $isCover = filter_var((string) $img['cover'], FILTER_VALIDATE_BOOLEAN);
                            ListingMedia::create([
                                'listing_id' => $listing->id,
                                'file_path' => $url,
                                'file_url' => $url,
                                'alt_text' => trim((string) $img['alt']) ?: null,
                                'sort_order' => is_numeric((string) $img['order']) ? (int) $img['order'] : ++$order,
                                'is_cover' => $isCover && ! $hasCover,
                            ]);
                            if ($isCover) $hasCover = true;
                        }
                        // Kapak işaretlenmemişse ilk görsel kapak olur.
                        if (! $hasCover) {
                            $listing->media()->orderBy('sort_order')->first()?->update(['is_cover' => true]);
                        }
                    }
                });
            } catch (ValidationException $e) {
                $errors[] = ['slug' => $label, 'message' => collect($e->errors())->flatten()->implode(' ')];
            } catch (\Throwable $e) {
                $errors[] = ['slug' => $label, 'message' => $e->getMessage()];
            }
        }

        return response()->json([
            'data' => [
                'created' => $created,
                'updated' => $updated,
                'errors' => $errors,
            ],
        ]);
    }
}
