<?php

namespace App\Http\Controllers\Admin\Category;

use App\Http\Controllers\Controller;
use App\Http\Requests\Category\CategoryStoreRequest;
use App\Http\Requests\Category\CategoryUpdateRequest;
use App\Models\Category;
use App\Models\Product;
use App\Models\Scopes\ActiveProductScope;
use App\Service\Category\CategoryService;
use Illuminate\Http\Request;
use Inertia\Inertia;

class CategoryController extends Controller
{
    private function flattenHierarchy($groupedByParent, $parentId = null, $includeMap = null)
    {
        $children = $groupedByParent
            ->get($parentId, collect())
            ->sortBy([
                ['ordering', 'asc'],
                ['id', 'desc'],
            ]);

        $result = [];

        foreach ($children as $node) {
            $shouldInclude = is_null($includeMap) || isset($includeMap[$node->id]);
            if (! $shouldInclude) {
                continue;
            }

            $result[] = $node;
            $result = array_merge(
                $result,
                $this->flattenHierarchy($groupedByParent, $node->id, $includeMap)
            );
        }

        return $result;
    }

    private function collectAncestorIds($categoryId, $parentById)
    {
        $ancestorIds = [];
        $current = $categoryId;

        while (! empty($parentById[$current])) {
            $parentId = $parentById[$current];
            $ancestorIds[] = $parentId;
            $current = $parentId;
        }

        return $ancestorIds;
    }

    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        return Inertia::render('Category/Category');
    }

    public function view(Request $request)
    {
        // Check if pagination is requested
        $isPaginationRequest = request()->filled('page') || request()->filled('perPage') || request()->filled('search') || request()->filled('type');

        if ($isPaginationRequest) {

            // Handle pagination request
            $page = request()->get('page', 1);
            $perPage = request()->get('perPage', 10);
            $search = request()->get('search', '');
            $typeFilter = request()->get('type');

            $query = Category::with('Parent')->withCount('products');

            // Determine permission-based default type filter using Spatie permissions
            $canRow = auth()->user()->can('product_for_row_material');
            $canFinish = auth()->user()->can('product_for_finish_product');

            if ($request->filled('type')) {

                $query->where('type', $request->get('type'));
            } else {

                if ($canRow && ! $canFinish) {
                    $query->where('type', 'row_product');
                } elseif ($canFinish && ! $canRow) {
                    $query->where('type', 'finish_product');
                }

            }

            // Apply type filter
            if (! empty($typeFilter)) {
                $query->where('type', $typeFilter);
            }

            // Get all categories first (for hierarchical structure) - without search filter
            $allCategoriesQuery = Category::with('Parent')->withCount('products');

            // Apply type filters to all categories query
            if ($request->filled('type')) {
                $allCategoriesQuery->where('type', $request->get('type'));
            } else {
                if ($canRow && ! $canFinish) {
                    $allCategoriesQuery->where('type', 'row_product');
                } elseif ($canFinish && ! $canRow) {
                    $allCategoriesQuery->where('type', 'finish_product');
                }
            }

            if (! empty($typeFilter)) {
                $allCategoriesQuery->where('type', $typeFilter);
            }

            $allCategories = $allCategoriesQuery->get();

            // Apply search filter to find matching categories
            $matchingCategoryIds = [];
            if (! empty($search)) {
                $searchQuery = Category::with('Parent')->withCount('products');

                // Apply same type filters
                if ($request->filled('type')) {
                    $searchQuery->where('type', $request->get('type'));
                } else {
                    if ($canRow && ! $canFinish) {
                        $searchQuery->where('type', 'row_product');
                    } elseif ($canFinish && ! $canRow) {
                        $searchQuery->where('type', 'finish_product');
                    }
                }

                if (! empty($typeFilter)) {
                    $searchQuery->where('type', $typeFilter);
                }

                $searchQuery->where(function ($q) use ($search) {
                    $q->where('name', 'LIKE', "%{$search}%")
                        ->orWhere('type', 'LIKE', "%{$search}%")
                        ->orWhereHas('Parent', function ($subQuery) use ($search) {
                            $subQuery->where('name', 'LIKE', "%{$search}%");
                        });
                });

                $matchingCategories = $searchQuery->get();
                $matchingCategoryIds = $matchingCategories->pluck('id')->toArray();

                // Also include parents of matching children
                $matchingChildren = $matchingCategories->whereNotNull('parent_id');
                $parentIds = $matchingChildren->pluck('parent_id')->unique()->toArray();
                $matchingCategoryIds = array_unique(array_merge($matchingCategoryIds, $parentIds));
            }

            $groupedByParent = $allCategories->groupBy('parent_id');
            $includeMap = null;

            if (! empty($search)) {
                $parentById = $allCategories
                    ->pluck('parent_id', 'id')
                    ->toArray();

                $includeIds = $matchingCategoryIds;
                foreach ($matchingCategoryIds as $matchedId) {
                    $includeIds = array_merge(
                        $includeIds,
                        $this->collectAncestorIds($matchedId, $parentById)
                    );
                }

                $includeMap = array_flip(array_unique($includeIds));
            }

            $hierarchicalData = $this->flattenHierarchy($groupedByParent, null, $includeMap);

            // Apply pagination manually
            $total = count($hierarchicalData);
            $offset = ($page - 1) * $perPage;
            $paginatedData = array_slice($hierarchicalData, $offset, $perPage);

            return response()->json([
                'data' => $paginatedData,
                'total' => $total,
            ]);
        } else {
            // Handle regular request - return parent dropdown data
            $parent = Category::whereNull('parent_id')
                ->with([
                    'childRecursive' => function ($q) {
                        $q->orderBy('ordering')->orderByDesc('id');
                    },
                ])
                ->withCount('products')
                ->orderBy('ordering')
                ->orderByDesc('id')
                ->get();

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

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(CategoryStoreRequest $request)
    {

        CategoryService::CategoryCreate(request()->toArray());

        $parent = Category::whereNull('parent_id')
            ->with([
                'childRecursive',
            ])
            ->withCount('products')
            ->orderBy('ordering')
            ->orderByDesc('id')
            ->get();

        return response()->json(['success' => 'Categroy create successfully', 'parent' => $parent]);
    }

    /**
     * Display the specified resource.
     */
    public function show(string $id) {}

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(string $id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(CategoryUpdateRequest $request, string $id)
    {
        CategoryService::CategoryUpdate(request()->all(), $id);
        $parent = Category::whereNull('parent_id')
            ->with([
                'childRecursive',
            ])
            ->withCount('products')
            ->orderBy('ordering')
            ->orderByDesc('id')
            ->get();

        return response()->json(['success' => 'Categroy update successfully',  'parent' => $parent]);
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(string $id)
    {

        // Find the category by ID

        $category = Category::findOrFail($id);
        $parent = Category::where('parent_id', $id)->first();
        $category_id = Product::withoutGlobalScope(ActiveProductScope::class)->where('category_id', $id)->first();
        if ($parent) {
            return response()->json(['error' => 'This Category have a child'], 422);
        } elseif ($category_id) {
            return response()->json(['error' => 'This Category have a  product'], 422);
        }
        if ($category->image) {
            unlink('upload/'.$category->image);
        }
        // Delete the category
        $category->delete();

        $parent = Category::whereNull('parent_id')
            ->with([
                'childRecursive',
            ])
            ->withCount('products')
            ->orderBy('ordering')
            ->orderByDesc('id')
            ->get();

        return response()->json(['success' => 'Category Delete successfully', 'parent' => $parent]);
    }
}
