<?php

namespace App\Http\Controllers;

use App\Models\Category;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class CategoryController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(Request $request): JsonResponse
    {
        $query = Category::query();

        // Filter by parent_id - if null, show only main categories; if set, show subcategories
        if ($request->has('parent_id')) {
            if ($request->parent_id === 'null' || $request->parent_id === null) {
                $query->whereNull('parent_id');
            } else {
                $query->where('parent_id', $request->parent_id);
            }
        } else {
            // By default, show only main categories
            $query->whereNull('parent_id');
        }

        // Search by name or code
        if ($request->has('search')) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                    ->orWhere('name_km', 'like', "%{$search}%")
                    ->orWhere('code', 'like', "%{$search}%");
            });
        }

        // Sorting
        $sortBy = $request->get('sort_by', 'created_at');
        $sortOrder = $request->get('sort_order', 'desc');
        $sortBy = in_array($sortBy, ['name', 'name_km', 'code', 'created_at', 'updated_at'], true) ? $sortBy : 'created_at';
        $sortOrder = strtolower((string) $sortOrder) === 'asc' ? 'asc' : 'desc';
        $query->orderBy($sortBy, $sortOrder);

        // Pagination
        $perPage = min(100, max(1, (int) $request->get('per_page', 15)));
        $categories = $query->with('subcategories')->paginate($perPage);

        $paginated = $categories->toArray();
        foreach ($paginated['data'] as $index => $item) {
            $paginated[$index] = $item;
        }

        return response()->json([
            'success' => true,
            'data' => $paginated,
        ]);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255',
            'code' => 'required|string|max:255|unique:categories,code',
            'image' => 'nullable|string|max:500',
            'description' => 'nullable|string',
            'name_km' => 'nullable|string|max:255',
            'description_km' => 'nullable|string',
            'parent_id' => 'nullable|exists:categories,id',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'errors' => $validator->errors(),
            ], 422);
        }

        // If parent_id is provided, verify it's a main category (not a subcategory)
        if ($request->has('parent_id') && $request->parent_id !== null) {
            $parent = Category::find($request->parent_id);
            if (! $parent) {
                return response()->json([
                    'success' => false,
                    'errors' => ['parent_id' => ['Parent category not found']],
                ], 422);
            }
            if ($parent->parent_id !== null) {
                return response()->json([
                    'success' => false,
                    'errors' => ['parent_id' => ['Cannot create subcategory of a subcategory. Parent must be a main category.']],
                ], 422);
            }
        }

        $category = Category::create($validator->validated());
        $category->load('parent', 'subcategories');

        $message = $category->parent_id ? 'Subcategory created successfully' : 'Category created successfully';

        return response()->json([
            'success' => true,
            'message' => $message,
            'data' => $category,
        ], 201);
    }

    /**
     * Display the specified resource.
     */
    public function show(string $id): JsonResponse
    {
        $category = Category::with(['parent', 'subcategories'])->find($id);

        if (! $category) {
            return response()->json([
                'success' => false,
                'message' => 'Category not found',
            ], 404);
        }

        // Load products count
        $category->products_count = $category->products()->count();

        // Load subcategories count if it's a main category
        if ($category->isMainCategory()) {
            $category->subcategories_count = $category->subcategories()->count();
        }

        return response()->json([
            'success' => true,
            'data' => $category,
        ]);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, string $id): JsonResponse
    {
        $category = Category::find($id);

        if (! $category) {
            return response()->json([
                'success' => false,
                'message' => 'Category not found',
            ], 404);
        }

        $validator = Validator::make($request->all(), [
            'name' => 'sometimes|required|string|max:255',
            'code' => 'sometimes|required|string|max:255|unique:categories,code,'.$id,
            'image' => 'nullable|string|max:500',
            'description' => 'nullable|string',
            'name_km' => 'nullable|string|max:255',
            'description_km' => 'nullable|string',
            'parent_id' => 'nullable|exists:categories,id',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'errors' => $validator->errors(),
            ], 422);
        }

        // Prevent circular references - category cannot be its own parent
        if ($request->has('parent_id') && $request->parent_id == $id) {
            return response()->json([
                'success' => false,
                'errors' => ['parent_id' => ['Category cannot be its own parent']],
            ], 422);
        }

        // If parent_id is provided, verify it's a main category (not a subcategory)
        if ($request->has('parent_id') && $request->parent_id !== null) {
            $parent = Category::find($request->parent_id);
            if (! $parent) {
                return response()->json([
                    'success' => false,
                    'errors' => ['parent_id' => ['Parent category not found']],
                ], 422);
            }
            if ($parent->parent_id !== null) {
                return response()->json([
                    'success' => false,
                    'errors' => ['parent_id' => ['Cannot set subcategory as parent. Parent must be a main category.']],
                ], 422);
            }
            // Prevent making a category with subcategories into a subcategory
            if ($category->subcategories()->count() > 0) {
                return response()->json([
                    'success' => false,
                    'errors' => ['parent_id' => ['Cannot convert category with subcategories into a subcategory']],
                ], 422);
            }
        }

        $category->update($validator->validated());
        $category->load('parent', 'subcategories');

        $message = $category->parent_id ? 'Subcategory updated successfully' : 'Category updated successfully';

        return response()->json([
            'success' => true,
            'message' => $message,
            'data' => $category->fresh(['parent', 'subcategories']),
        ]);
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(string $id): JsonResponse
    {
        $category = Category::find($id);

        if (! $category) {
            return response()->json([
                'success' => false,
                'message' => 'Category not found',
            ], 404);
        }

        // Check if category has products
        $productsCount = $category->products()->count();
        if ($productsCount > 0) {
            $type = $category->isSubcategory() ? 'subcategory' : 'category';

            return response()->json([
                'success' => false,
                'message' => "Cannot delete {$type}. It has {$productsCount} product(s) associated with it.",
            ], 422);
        }

        // Check if main category has subcategories
        if ($category->isMainCategory()) {
            $subcategoriesCount = $category->subcategories()->count();
            if ($subcategoriesCount > 0) {
                return response()->json([
                    'success' => false,
                    'message' => "Cannot delete category. It has {$subcategoriesCount} subcategory(ies). Please delete or reassign subcategories first.",
                ], 422);
            }
        }

        $category->delete();

        $message = $category->isSubcategory() ? 'Subcategory deleted successfully' : 'Category deleted successfully';

        return response()->json([
            'success' => true,
            'message' => $message,
        ]);
    }

    /**
     * Get subcategories for a specific category.
     */
    public function getSubcategories(Request $request, string $id): JsonResponse
    {
        $category = Category::find($id);

        if (! $category) {
            return response()->json([
                'success' => false,
                'message' => 'Category not found',
            ], 404);
        }

        $query = $category->subcategories();

        // Search by name or code
        if ($request->has('search')) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                    ->orWhere('name_km', 'like', "%{$search}%")
                    ->orWhere('code', 'like', "%{$search}%");
            });
        }

        // Sorting
        $sortBy = $request->get('sort_by', 'created_at');
        $sortOrder = $request->get('sort_order', 'desc');
        $sortBy = in_array($sortBy, ['name', 'name_km', 'code', 'created_at', 'updated_at'], true) ? $sortBy : 'created_at';
        $sortOrder = strtolower((string) $sortOrder) === 'asc' ? 'asc' : 'desc';
        $query->orderBy($sortBy, $sortOrder);

        // Pagination
        $perPage = min(100, max(1, (int) $request->get('per_page', 15)));
        $subcategories = $query->paginate($perPage);

        return response()->json([
            'success' => true,
            'data' => $subcategories,
        ]);
    }
}
