<?php

namespace App\Services;

use App\Constants\SystemFields;
use App\Models\Commons\Category;
use App\Models\ItemMaster\ItemField;
use App\Models\Products\CommonCode;
use App\Models\Products\Product;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class ProductService extends Service
{
    /**
     * products 테이블의 고정 컬럼 목록 조회 (SystemFields + ItemField 기반)
     */
    private function getKnownFields(): array
    {
        $tenantId = $this->tenantId();

        // 1. SystemFields에서 products 테이블 고정 컬럼
        $systemFields = SystemFields::getReservedKeys(SystemFields::SOURCE_TABLE_PRODUCTS);

        // 2. ItemField에서 storage_type='column'인 필드의 field_key 조회
        $columnFields = ItemField::where('tenant_id', $tenantId)
            ->where('source_table', 'products')
            ->where('storage_type', 'column')
            ->whereNotNull('field_key')
            ->pluck('field_key')
            ->toArray();

        // 3. 추가적인 API 전용 필드 (DB 컬럼이 아니지만 API에서 사용하는 필드)
        $apiFields = ['item_type', 'type_code', 'bom'];

        return array_unique(array_merge($systemFields, $columnFields, $apiFields));
    }

    /**
     * 정의된 필드 외의 동적 필드를 options로 추출
     */
    private function extractDynamicOptions(array $params): array
    {
        $knownFields = $this->getKnownFields();

        $dynamicOptions = [];
        foreach ($params as $key => $value) {
            if (! in_array($key, $knownFields) && $value !== null && $value !== '') {
                $dynamicOptions[$key] = $value;
            }
        }

        return $dynamicOptions;
    }

    /**
     * 기존 options 배열과 동적 필드를 병합
     */
    private function mergeOptionsWithDynamic($existingOptions, array $dynamicOptions): array
    {
        if (! is_array($existingOptions) || empty($existingOptions)) {
            return $dynamicOptions;
        }

        $isAssoc = array_keys($existingOptions) !== range(0, count($existingOptions) - 1);

        if ($isAssoc) {
            return array_merge($existingOptions, $dynamicOptions);
        }

        foreach ($dynamicOptions as $key => $value) {
            $existingOptions[] = ['label' => $key, 'value' => $value];
        }

        return $existingOptions;
    }

    /**
     * options 입력을 [{label, value, unit}] 형태로 정규화
     */
    private function normalizeOptions(?array $in): ?array
    {
        if (! $in) {
            return null;
        }

        $isAssoc = array_keys($in) !== range(0, count($in) - 1);

        if ($isAssoc) {
            $out = [];
            foreach ($in as $k => $v) {
                $label = trim((string) $k);
                $value = is_scalar($v) ? trim((string) $v) : json_encode($v, JSON_UNESCAPED_UNICODE);
                if ($label !== '' || $value !== '') {
                    $out[] = ['label' => $label, 'value' => $value, 'unit' => ''];
                }
            }

            return $out ?: null;
        }

        $out = [];
        foreach ($in as $a) {
            if (! is_array($a)) {
                continue;
            }
            $label = trim((string) ($a['label'] ?? ''));
            $value = trim((string) ($a['value'] ?? ''));
            $unit = trim((string) ($a['unit'] ?? ''));

            if ($label === '' && $value === '') {
                continue;
            }

            $out[] = ['label' => $label, 'value' => $value, 'unit' => $unit];
        }

        return $out ?: null;
    }

    /**
     * 카테고리 트리 전체 조회 (parent_id = null 기준)
     */
    public function getCategory($request)
    {
        $parentId = $request->parentId ?? null;
        $group = $request->group ?? 'category';

        // 재귀적으로 트리 구성
        $list = $this->fetchCategoryTree($parentId, $group);

        return $list;
    }

    /**
     * 내부 재귀 함수 (하위 카테고리 트리 구조로 구성)
     */
    protected function fetchCategoryTree(?int $parentId = null)
    {
        $tenantId = $this->tenantId(); // Base Service에서 상속받은 메서드

        $query = Category::query()
            ->when($tenantId, fn ($q) => $q->where('tenant_id', $tenantId))
            ->when(
                is_null($parentId),
                fn ($q) => $q->whereNull('parent_id'),
                fn ($q) => $q->where('parent_id', $parentId)
            )
            ->where('is_active', 1)
            ->orderBy('sort_order');

        $categories = $query->get();

        foreach ($categories as $category) {
            $children = $this->fetchCategoryTree($category->id);
            $category->setRelation('children', $children);
        }

        return $categories;
    }

    /**
     * (예시) 기존의 flat 리스트 조회
     */
    public static function getCategoryFlat($group = 'category')
    {
        $query = CommonCode::where('code_group', $group)->whereNull('parent_id');

        return $query->get();
    }

    // 목록/검색
    public function index(array $params)
    {
        $tenantId = $this->tenantId();

        $size = (int) ($params['size'] ?? 20);
        $q = trim((string) ($params['q'] ?? ''));
        $categoryId = $params['category_id'] ?? null;
        $productType = $params['product_type'] ?? null; // PRODUCT|PART|SUBASSEMBLY...
        $active = $params['active'] ?? null;       // 1/0

        $query = Product::query()
            ->with('category:id,name') // 필요한 컬럼만 가져오기
            ->where('tenant_id', $tenantId);

        if ($q !== '') {
            $query->where(function ($w) use ($q) {
                $w->where('name', 'like', "%{$q}%")
                    ->orWhere('code', 'like', "%{$q}%")
                    ->orWhere('description', 'like', "%{$q}%");
            });
        }
        if ($categoryId) {
            $query->where('category_id', (int) $categoryId);
        }
        if ($productType) {
            $query->where('product_type', $productType);
        }
        // Note: is_active 필드는 하이브리드 구조로 전환하면서 제거됨
        // 필요시 attributes JSON이나 별도 필드로 관리
        // if ($active !== null && $active !== '') {
        //     $query->where('is_active', (int) $active);
        // }

        $paginator = $query->orderBy('id')->paginate($size);

        // 날짜 형식을 위해 분리
        $paginator->setCollection(
            $paginator->getCollection()->transform(function ($item) {
                $arr = $item->toArray();
                $arr['created_at'] = $item->created_at
                    ? $item->created_at->format('Y-m-d')
                    : null;

                return $arr;
            })
        );

        return $paginator;
    }

    // 생성
    public function store(array $data)
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 동적 필드를 options에 병합
        $dynamicOptions = $this->extractDynamicOptions($data);
        if (! empty($dynamicOptions)) {
            $existingOptions = $data['options'] ?? [];
            $data['options'] = $this->mergeOptionsWithDynamic($existingOptions, $dynamicOptions);
        }

        // options 정규화
        if (isset($data['options'])) {
            $data['options'] = $this->normalizeOptions($data['options']);
        }

        $payload = $data;

        // tenant별 code 유니크 수동 체크
        $dup = Product::query()
            ->where('tenant_id', $tenantId)
            ->where('code', $payload['code'])
            ->exists();
        if ($dup) {
            throw new BadRequestHttpException(__('error.duplicate_key'));
        }

        // 기본값 설정
        $payload['tenant_id'] = $tenantId;
        $payload['created_by'] = $userId;
        $payload['is_sellable'] = $payload['is_sellable'] ?? true;
        $payload['is_purchasable'] = $payload['is_purchasable'] ?? false;
        $payload['is_producible'] = $payload['is_producible'] ?? true;

        return Product::create($payload);
    }

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

        return $p;
    }

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

        $p = Product::query()->where('tenant_id', $tenantId)->find($id);
        if (! $p) {
            throw new BadRequestHttpException(__('error.not_found'));
        }

        // 동적 필드를 options에 병합
        $dynamicOptions = $this->extractDynamicOptions($data);
        if (! empty($dynamicOptions)) {
            $existingOptions = $data['options'] ?? [];
            $data['options'] = $this->mergeOptionsWithDynamic($existingOptions, $dynamicOptions);
        }

        // options 정규화
        if (isset($data['options'])) {
            $data['options'] = $this->normalizeOptions($data['options']);
        }

        $payload = $data;

        // code 변경 시 중복 체크
        if (isset($payload['code']) && $payload['code'] !== $p->code) {
            $dup = Product::query()
                ->where('tenant_id', $tenantId)
                ->where('code', $payload['code'])
                ->exists();
            if ($dup) {
                throw new BadRequestHttpException(__('error.duplicate_key'));
            }
        }

        $payload['updated_by'] = $userId;
        $p->update($payload);

        return $p->refresh();
    }

    // 삭제(soft)
    public function destroy(int $id): void
    {
        $tenantId = $this->tenantId();
        $p = Product::query()->where('tenant_id', $tenantId)->find($id);
        if (! $p) {
            throw new BadRequestHttpException(__('error.not_found'));
        }
        $p->delete();
    }

    // 간편 검색(모달/드롭다운)
    public function search(array $params)
    {
        $tenantId = $this->tenantId();
        $q = trim((string) ($params['q'] ?? ''));
        $lim = (int) ($params['limit'] ?? 20);

        $qr = Product::query()->where('tenant_id', $tenantId);
        if ($q !== '') {
            $qr->where(function ($w) use ($q) {
                $w->where('name', 'like', "%{$q}%")
                    ->orWhere('code', 'like', "%{$q}%");
            });
        }

        return $qr->orderBy('name')->limit($lim)->get(['id', 'code', 'name', 'product_type', 'category_id']);
    }

    // Note: toggle 메서드는 is_active 필드 제거로 인해 비활성화됨
    // 필요시 attributes JSON이나 별도 필드로 구현
    // public function toggle(int $id)
    // {
    //     $tenantId = $this->tenantId();
    //     $userId = $this->apiUserId();
    //
    //     $p = Product::query()->where('tenant_id', $tenantId)->find($id);
    //     if (! $p) {
    //         throw new BadRequestHttpException(__('error.not_found'));
    //     }
    //
    //     $p->is_active = $p->is_active ? 0 : 1;
    //     $p->updated_by = $userId;
    //     $p->save();
    //
    //     return ['id' => $p->id, 'is_active' => (int) $p->is_active];
    // }
}
