<?php

namespace App\Http\Controllers\Agency\Product;

use App\Http\Controllers\Controller;
use App\Models\Product\ProductCategory;
use App\Models\Product\ProductType;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

/**
 * Ürün listelerindeki klasör (kategori) işlemleri.
 *
 * Listede sağ tıklanan satır buradan taşınır: ürün başka bir kategoriye, kategori
 * başka bir üst kategoriye. Ürün listeleri tip başına ayrı controller'larda
 * olduğu için taşıma tek yerde toplandı; istekteki "type" anahtarı hangi ürün
 * modelinin hedeflendiğini söyler.
 */
class ProductFolderController extends Controller
{
    /** Liste anahtarı → [ürün modeli, ürün tipi slug'ı]. */
    private const TYPES = [
        'kultur-turlari' => [\App\Models\Tour\Tour::class, 'kultur-turu'],
        'gunubirlik-turlar' => [\App\Models\DayTour\DayTour::class, 'gunubirlik-tur'],
        'yurtdisi-turlari' => [\App\Models\InternationalTour\InternationalTour::class, 'yurtdisi-turu'],
    ];

    private function resolveType(string $key): array
    {
        abort_unless(isset(self::TYPES[$key]), 404, 'Bilinmeyen ürün listesi.');

        [$modelClass, $slug] = self::TYPES[$key];
        $productType = ProductType::where('slug', $slug)->first();
        abort_unless($productType, 404, 'Ürün tipi bulunamadı.');

        return [$modelClass, $productType];
    }

    /** Aynı acentedeki ve aynı ürün tipindeki kategori değilse 404. */
    private function categoryOrFail(int $id, ProductType $productType): ProductCategory
    {
        return ProductCategory::where('id', $id)
            ->where('agency_id', Auth::user()->currentAgencyId())
            ->where('product_type_id', $productType->id)
            ->firstOrFail();
    }

    /**
     * Taşıma penceresinin kategori ağacı: girintili tek düz liste.
     * "Kategorisiz" seçeneği arayüzde eklenir (category_id = null).
     */
    public function tree(string $type)
    {
        [, $productType] = $this->resolveType($type);

        $all = ProductCategory::where('product_type_id', $productType->id)
            ->where('agency_id', Auth::user()->currentAgencyId())
            ->orderBy('sort_order')
            ->orderBy('name')
            ->get(['id', 'parent_id', 'name']);

        $rows = [];
        $walk = function ($parentId, $depth) use (&$walk, $all, &$rows) {
            foreach ($all->where('parent_id', $parentId) as $c) {
                $rows[] = ['id' => (int) $c->id, 'name' => $c->name, 'depth' => $depth];
                $walk($c->id, $depth + 1);
            }
        };
        $walk(null, 0);

        return response()->json(['categories' => $rows]);
    }

    /**
     * Ürünü bir klasöre taşı. category_id boşsa ürün kategorisiz kalır
     * (kök klasörde görünür). Klasör mantığı tek kategori üzerinden yürüdüğü
     * için mevcut kategori bağları bu değerle değiştirilir.
     */
    public function moveProduct(Request $request, string $type)
    {
        [$modelClass, $productType] = $this->resolveType($type);

        $data = $request->validate([
            'id' => 'required|integer',
            'category_id' => 'nullable|integer',
        ]);

        $product = $modelClass::where('id', $data['id'])
            ->where('agency_id', Auth::user()->currentAgencyId())
            ->firstOrFail();

        if (!$product->product_id) {
            return response()->json(['success' => false, 'message' => 'Bu kaydın ürün bağlantısı yok.'], 422);
        }

        $categoryId = $data['category_id'] ?? null;
        if ($categoryId) {
            $this->categoryOrFail((int) $categoryId, $productType);
        }

        $product->product->categories()->sync($categoryId ? [(int) $categoryId] : []);

        return response()->json([
            'success' => true,
            'message' => $categoryId ? 'Kayıt klasöre taşındı.' : 'Kayıt kategorisiz klasöre alındı.',
        ]);
    }

    /**
     * Kategoriyi başka bir kategorinin altına taşı. parent_id boşsa köke çıkar.
     * Bir kategori kendi altına taşınamaz — aksi hâlde ağaç kopar.
     */
    public function moveCategory(Request $request, string $type)
    {
        [, $productType] = $this->resolveType($type);

        $data = $request->validate([
            'id' => 'required|integer',
            'parent_id' => 'nullable|integer',
        ]);

        $category = $this->categoryOrFail((int) $data['id'], $productType);
        $parentId = $data['parent_id'] ?? null;

        if ($parentId) {
            $parent = $this->categoryOrFail((int) $parentId, $productType);

            if ((int) $parent->id === (int) $category->id) {
                return response()->json(['success' => false, 'message' => 'Kategori kendi içine taşınamaz.'], 422);
            }

            if ($this->isDescendant($category, (int) $parent->id, $productType)) {
                return response()->json(['success' => false, 'message' => 'Kategori kendi alt klasörüne taşınamaz.'], 422);
            }
        }

        $category->parent_id = $parentId ?: null;
        $category->level = $parentId ? ((int) ProductCategory::find($parentId)->level + 1) : 0;
        $category->save();

        return response()->json(['success' => true, 'message' => 'Klasör taşındı.']);
    }

    /** $candidateId, $category'nin alt ağacında mı? */
    private function isDescendant(ProductCategory $category, int $candidateId, ProductType $productType): bool
    {
        $all = ProductCategory::where('product_type_id', $productType->id)
            ->where('agency_id', Auth::user()->currentAgencyId())
            ->get(['id', 'parent_id']);

        $cursor = $all->firstWhere('id', $candidateId);
        $guard = 0;

        while ($cursor && $guard++ < 50) {
            if ((int) $cursor->parent_id === (int) $category->id) {
                return true;
            }
            $cursor = $cursor->parent_id ? $all->firstWhere('id', $cursor->parent_id) : null;
        }

        return false;
    }
}
