<?php

namespace App\Services;

use App\Models\Commons\Category;
use Illuminate\Support\Facades\Validator;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class CategoryService extends Service
{
    /** 목록(검색/페이징) */
    public function index(array $params)
    {
        $tenantId = $this->tenantId();

        $page = (int) ($params['page'] ?? 1);
        $size = (int) ($params['size'] ?? 20);
        $q = trim((string) ($params['q'] ?? ''));
        $pid = $params['parent_id'] ?? null;
        $onlyActive = $params['only_active'] ?? null;

        $query = Category::query()->where('tenant_id', $tenantId);

        if ($q !== '') {
            $query->where(function ($qq) use ($q) {
                $qq->where('name', 'like', "%{$q}%")
                    ->orWhere('code', 'like', "%{$q}%");
            });
        }
        if ($pid !== null) {
            $query->where('parent_id', (int) $pid);
        }
        if ($onlyActive !== null) {
            $query->where('is_active', (int) (bool) $onlyActive);
        }

        $query->orderBy('parent_id')->orderBy('sort_order')->orderBy('id');

        return $query->paginate($size, ['*'], 'page', $page);
    }

    /** 단건 */
    public function show(int $id)
    {
        $tenantId = $this->tenantId();
        $cat = Category::where('tenant_id', $tenantId)->find($id);
        if (! $cat) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        return $cat;
    }

    /** 생성 */
    public function store(array $params)
    {
        $tenantId = $this->tenantId();
        $uid = $this->apiUserId();

        $v = Validator::make($params, [
            'parent_id' => 'nullable|integer|min:1',
            'code' => 'nullable|string|max:50',
            'name' => 'required|string|max:100',
            'description' => 'nullable|string|max:255',
            'is_active' => 'nullable|boolean',
            'sort_order' => 'nullable|integer|min:0',
        ]);
        if ($v->fails()) {
            throw new BadRequestHttpException($v->errors()->first());
        }

        $data = $v->validated();
        $data['tenant_id'] = $tenantId;
        $data['created_by'] = $uid;
        $data['is_active'] = (int) ($data['is_active'] ?? 1);
        $data['sort_order'] = $data['sort_order'] ?? 0;

        return Category::create($data);
    }

    /** 수정 */
    public function update(int $id, array $params)
    {
        $tenantId = $this->tenantId();
        $uid = $this->apiUserId();

        $cat = Category::where('tenant_id', $tenantId)->find($id);
        if (! $cat) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        $v = Validator::make($params, [
            'parent_id' => 'nullable|integer|min:1',
            'code' => 'nullable|string|max:50',
            'name' => 'sometimes|required|string|max:100',
            'description' => 'nullable|string|max:255',
            'is_active' => 'nullable|boolean',
            'sort_order' => 'nullable|integer|min:0',
        ]);
        if ($v->fails()) {
            throw new BadRequestHttpException($v->errors()->first());
        }

        $payload = $v->validated();
        $payload['updated_by'] = $uid;

        $cat->update($payload);

        return $cat->refresh();
    }

    /** 삭제(soft) */
    public function destroy(int $id)
    {
        $tenantId = $this->tenantId();
        $uid = $this->apiUserId();

        $cat = Category::where('tenant_id', $tenantId)->find($id);
        if (! $cat) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        // (옵션) 하위 존재 검사
        $hasChild = Category::where('tenant_id', $tenantId)->where('parent_id', $id)->exists();
        if ($hasChild) {
            throw new BadRequestHttpException(__('error.child_exists'));
        }

        $cat->deleted_by = $uid;
        $cat->save();
        $cat->delete();

        return 'success';
    }

    /** 활성/비활성 토글 */
    public function toggle(int $id)
    {
        $tenantId = $this->tenantId();
        $cat = Category::where('tenant_id', $tenantId)->find($id);
        if (! $cat) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        $cat->is_active = $cat->is_active ? 0 : 1;
        $cat->save();

        return $cat->refresh();
    }

    /** 부모/순서 이동 */
    public function move(int $id, array $params)
    {
        $tenantId = $this->tenantId();
        $v = Validator::make($params, [
            'parent_id' => 'nullable|integer|min:1',
            'sort_order' => 'nullable|integer|min:0',
        ]);
        if ($v->fails()) {
            throw new BadRequestHttpException($v->errors()->first());
        }

        $cat = Category::where('tenant_id', $tenantId)->find($id);
        if (! $cat) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        $payload = $v->validated();
        $cat->update($payload);

        return $cat->refresh();
    }

    /** 정렬순서 일괄 변경: [{id, sort_order}] */
    public function reorder(array $params)
    {
        $tenantId = $this->tenantId();
        $items = $params['items'] ?? null;
        if (! is_array($items) || empty($items)) {
            throw new BadRequestHttpException(__('validation.required', ['attribute' => 'items']));
        }
        foreach ($items as $row) {
            if (! isset($row['id'])) {
                continue;
            }
            Category::where('tenant_id', $tenantId)
                ->where('id', (int) $row['id'])
                ->update(['sort_order' => (int) ($row['sort_order'] ?? 0)]);
        }

        return 'success';
    }

    /** 트리 조회 (parent_id=null 기준 전체) */
    public function tree(array $params)
    {
        $tenantId = $this->tenantId();
        $onlyActive = (bool) ($params['only_active'] ?? false);
        $codeGroup = $params['code_group'] ?? null;

        $q = Category::where('tenant_id', $tenantId)
            ->when($onlyActive, fn ($qq) => $qq->where('is_active', 1))
            ->when($codeGroup, fn ($qq) => $qq->where('code_group', $codeGroup))
            ->orderBy('parent_id')->orderBy('sort_order')->orderBy('id')
            ->get(['id', 'parent_id', 'code', 'code_group', 'name', 'is_active', 'sort_order']);

        // 최상위 카테고리 ID 수집 (해당 code_group의 parent_id가 null이거나, 다른 code_group의 카테고리를 가리키는 경우)
        $categoryIds = $q->pluck('id')->toArray();
        $rootIds = $q->filter(fn ($c) => $c->parent_id === null || ! in_array($c->parent_id, $categoryIds))->pluck('id')->toArray();

        $byParent = [];
        foreach ($q as $c) {
            $parentKey = in_array($c->id, $rootIds) ? 0 : ($c->parent_id ?? 0);
            $byParent[$parentKey][] = $c;
        }

        $build = function ($pid) use (&$build, &$byParent) {
            $nodes = $byParent[$pid] ?? [];

            return array_map(function ($n) use ($build) {
                return [
                    'id' => $n->id,
                    'code' => $n->code,
                    'name' => $n->name,
                    'is_active' => (int) $n->is_active,
                    'sort_order' => (int) $n->sort_order,
                    'children' => $build($n->id),
                ];
            }, $nodes);
        };

        return $build(0);
    }
}
