<?php

namespace App\Services;

use App\Models\Tenants\SettingFieldDef;
use App\Models\Tenants\TenantFieldSetting;
use App\Models\Tenants\TenantOptionGroup;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

class TenantFieldSettingService
{
    /** 활성 테넌트 ID 조회 (공통) */
    protected static function tenantId(): ?int
    {
        return app('tenant_id'); // 미들웨어에서 주입된 테넌트 ID 가정
    }

    /** 효과값 1개 빌드: 전역정의 + 테넌트설정 merge */
    protected static function buildEffectiveRow(SettingFieldDef $def, ?TenantFieldSetting $s): array
    {
        $enabled = $s ? (bool) $s->enabled : (bool) $def->is_core;

        return [
            'field_key' => $def->field_key,
            'label' => $def->label,
            'data_type' => $def->data_type,
            'input_type' => $def->input_type,
            'option_source' => $def->option_source,
            'option_payload' => $def->option_payload,
            'storage_area' => $def->storage_area,
            'storage_key' => $def->storage_key,
            'is_core' => (bool) $def->is_core,
            // tenant overlay
            'enabled' => $enabled,
            'required' => $s ? (bool) $s->required : false,
            'sort_order' => $s ? (int) $s->sort_order : 0,
            'option_group_id' => $s ? $s->option_group_id : null,
            'code_group' => $s ? $s->code_group : null,
        ];
    }

    /**
     * [GET] 효과값 목록
     * - 코어(is_core=1)는 기본 enabled=true
     * - enabled=false는 제외
     * - sort_order → field_key 순 정렬
     */
    public static function index(array $params = [])
    {
        $tenantId = self::tenantId();
        if (! $tenantId) {
            return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
        }

        $defs = SettingFieldDef::query()
            ->orderByDesc('is_core')
            ->orderBy('field_key')
            ->get()
            ->keyBy('field_key');

        $settings = TenantFieldSetting::where('tenant_id', $tenantId)
            ->get()
            ->keyBy('field_key');

        $rows = [];
        foreach ($defs as $key => $def) {
            $s = $settings->get($key);
            $effective = self::buildEffectiveRow($def, $s);
            if ($effective['enabled'] !== true) {
                continue;
            }
            $rows[] = $effective;
        }

        usort($rows, fn ($a, $b) => ($a['sort_order'] <=> $b['sort_order']) ?: strcmp($a['field_key'], $b['field_key'])
        );

        return array_values($rows);
    }

    /**
     * [PUT] 대량 업서트
     * params:
     *  items: [{field_key, enabled?, required?, sort_order?, option_group_id?, code_group?}, ...]
     */
    public static function bulkUpsert(array $params = [])
    {
        $tenantId = self::tenantId();
        if (! $tenantId) {
            return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
        }

        $v = Validator::make($params, [
            'items' => ['required', 'array', 'min:1'],
            'items.*.field_key' => ['required', 'string', 'max:64', Rule::exists('setting_field_defs', 'field_key')],
            'items.*.enabled' => ['nullable', 'boolean'],
            'items.*.required' => ['nullable', 'boolean'],
            'items.*.sort_order' => ['nullable', 'integer'],
            'items.*.option_group_id' => ['nullable', 'integer'],
            'items.*.code_group' => ['nullable', 'string', 'max:50'],
        ]);

        if ($v->fails()) {
            return ['error' => $v->errors()->first(), 'code' => 422];
        }

        $payload = $v->validated();

        try {
            DB::transaction(function () use ($payload, $tenantId) {
                foreach ($payload['items'] as $row) {
                    // option_group_id 유효성(해당 테넌트 소유인지)
                    if (! empty($row['option_group_id'])) {
                        $exists = TenantOptionGroup::where('tenant_id', $tenantId)
                            ->where('id', $row['option_group_id'])
                            ->exists();
                        if (! $exists) {
                            throw new \RuntimeException('option_group_id is invalid for this tenant');
                        }
                    }

                    TenantFieldSetting::updateOrCreate(
                        ['tenant_id' => $tenantId, 'field_key' => $row['field_key']],
                        [
                            'enabled' => isset($row['enabled']) ? (int) $row['enabled'] : 0,
                            'required' => isset($row['required']) ? (int) $row['required'] : 0,
                            'sort_order' => isset($row['sort_order']) ? (int) $row['sort_order'] : 0,
                            'option_group_id' => $row['option_group_id'] ?? null,
                            'code_group' => $row['code_group'] ?? null,
                        ]
                    );
                }
            });
        } catch (\RuntimeException $e) {
            return ['error' => $e->getMessage(), 'code' => 422];
        } catch (\Throwable $e) {
            return ['error' => '저장 중 오류가 발생했습니다.', 'code' => 500];
        }

        return ['updated' => true];
    }

    /**
     * [PATCH] 단건 수정
     * - 응답은 FieldEffective 포맷으로 반환
     */
    public static function updateOne(string $fieldKey, array $params = [])
    {
        $tenantId = self::tenantId();
        if (! $tenantId) {
            return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
        }

        // 전역 key 존재 확인
        $def = SettingFieldDef::where('field_key', $fieldKey)->first();
        if (! $def) {
            return ['error' => 'field_key not found', 'code' => 404];
        }

        $v = Validator::make($params, [
            'enabled' => ['nullable', 'boolean'],
            'required' => ['nullable', 'boolean'],
            'sort_order' => ['nullable', 'integer'],
            'option_group_id' => ['nullable', 'integer'],
            'code_group' => ['nullable', 'string', 'max:50'],
        ]);

        if ($v->fails()) {
            return ['error' => $v->errors()->first(), 'code' => 422];
        }
        $data = $v->validated();

        // option_group_id 테넌트 소유 검증
        if (! empty($data['option_group_id'])) {
            $ok = TenantOptionGroup::where('tenant_id', $tenantId)
                ->where('id', $data['option_group_id'])
                ->exists();
            if (! $ok) {
                return ['error' => 'option_group_id is invalid for this tenant', 'code' => 422];
            }
        }

        try {
            $item = TenantFieldSetting::firstOrNew([
                'tenant_id' => $tenantId,
                'field_key' => $fieldKey,
            ]);

            // 제공된 키만 반영
            foreach (['enabled', 'required', 'sort_order', 'option_group_id', 'code_group'] as $k) {
                if (array_key_exists($k, $data)) {
                    $item->{$k} = $data[$k];
                }
            }
            $item->save();

            // 최신 설정 다시 로드하여 효과값으로 리턴
            $s = TenantFieldSetting::where('tenant_id', $tenantId)
                ->where('field_key', $fieldKey)
                ->first();

            $effective = self::buildEffectiveRow($def, $s);

            return $effective;

        } catch (\Throwable $e) {
            return ['error' => '수정 중 오류가 발생했습니다.', 'code' => 500];
        }
    }
}
