<?php

namespace App\Http\Controllers;

use App\Models\Category;
use App\Models\GlobalCategory;
use App\Models\Tenants\Tenant;
use App\Models\Tenants\TenantSetting;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Http;

class CategorySyncController extends Controller
{
    private ?string $remoteTenantName = null;

    /**
     * 현재 선택된 테넌트 ID
     */
    protected function getTenantId(): int
    {
        $tenantId = session('selected_tenant_id');

        return ($tenantId && $tenantId !== 'all') ? (int) $tenantId : 1;
    }

    /**
     * 환경 설정 조회 (메뉴 동기화와 공유)
     */
    private function getEnvironments(): array
    {
        $setting = TenantSetting::withoutGlobalScopes()
            ->where('tenant_id', $this->getTenantId())
            ->where('setting_group', 'menu_sync')
            ->where('setting_key', 'environments')
            ->first();

        return $setting?->setting_value ?? [
            'dev' => ['name' => '개발', 'url' => '', 'api_key' => ''],
            'prod' => ['name' => '운영', 'url' => '', 'api_key' => ''],
        ];
    }

    /**
     * 카테고리 동기화 페이지
     */
    public function index(Request $request): View|Response
    {
        if ($request->header('HX-Request')) {
            return response('', 200)->header('HX-Redirect', route('categories.sync.index'));
        }

        $environments = $this->getEnvironments();
        $selectedEnv = $request->get('env', 'dev');
        $selectedType = $request->get('type', 'global'); // global or tenant

        // 로컬 테넌트 정보
        $localTenant = Tenant::find($this->getTenantId());

        // 로컬 카테고리 조회 (타입 필터 적용)
        $localCategories = $this->getCategoryList($selectedType);

        // 원격 카테고리 조회
        $remoteCategories = [];
        $remoteError = null;
        $this->remoteTenantName = null;

        if (! empty($environments[$selectedEnv]['url'])) {
            try {
                $remoteCategories = $this->fetchRemoteCategories($environments[$selectedEnv], $selectedType);
            } catch (\Exception $e) {
                $remoteError = $e->getMessage();
            }
        }

        // 차이점 계산
        $diff = $this->calculateDiff($localCategories, $remoteCategories);

        return view('categories.sync', [
            'environments' => $environments,
            'selectedEnv' => $selectedEnv,
            'selectedType' => $selectedType,
            'localCategories' => $localCategories,
            'remoteCategories' => $remoteCategories,
            'remoteError' => $remoteError,
            'diff' => $diff,
            'localTenantName' => $localTenant?->company_name ?? '알 수 없음',
            'remoteTenantName' => $this->remoteTenantName,
        ]);
    }

    /**
     * 카테고리 Export API (다른 환경에서 호출)
     */
    public function export(Request $request): JsonResponse
    {
        // API Key 검증
        $apiKey = $request->header('X-Menu-Sync-Key');
        $validKey = config('app.menu_sync_api_key');

        if (empty($validKey) || $apiKey !== $validKey) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        $type = $request->get('type', 'all'); // global, tenant, or all
        $categories = $this->getCategoryList($type);

        $tenant = Tenant::find($this->getTenantId());

        return response()->json([
            'success' => true,
            'environment' => config('app.env'),
            'tenant_name' => $tenant?->company_name ?? '알 수 없음',
            'exported_at' => now()->toIso8601String(),
            'categories' => $categories,
        ]);
    }

    /**
     * 카테고리 Import API (다른 환경에서 호출)
     */
    public function import(Request $request): JsonResponse
    {
        // API Key 검증
        $apiKey = $request->header('X-Menu-Sync-Key');
        $validKey = config('app.menu_sync_api_key');

        if (empty($validKey) || $apiKey !== $validKey) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        $validated = $request->validate([
            'categories' => 'required|array',
            'categories.*.is_global' => 'required|boolean',
            'categories.*.tenant_id' => 'nullable|integer',
            'categories.*.code_group' => 'required|string|max:50',
            'categories.*.code' => 'required|string|max:50',
            'categories.*.name' => 'required|string|max:100',
            'categories.*.parent_code' => 'nullable|string|max:50',
            'categories.*.sort_order' => 'nullable|integer',
            'categories.*.description' => 'nullable|string',
            'categories.*.is_active' => 'nullable|boolean',
        ]);

        $imported = 0;
        $skipped = 0;

        foreach ($validated['categories'] as $catData) {
            if ($catData['is_global']) {
                // 글로벌 카테고리
                $exists = GlobalCategory::where('code_group', $catData['code_group'])
                    ->where('code', $catData['code'])
                    ->exists();

                if ($exists) {
                    $skipped++;

                    continue;
                }

                // 부모 찾기
                $parentId = null;
                if (! empty($catData['parent_code'])) {
                    $parent = GlobalCategory::where('code_group', $catData['code_group'])
                        ->where('code', $catData['parent_code'])
                        ->first();
                    $parentId = $parent?->id;
                }

                GlobalCategory::create([
                    'parent_id' => $parentId,
                    'code_group' => $catData['code_group'],
                    'code' => $catData['code'],
                    'name' => $catData['name'],
                    'sort_order' => $catData['sort_order'] ?? 0,
                    'description' => $catData['description'] ?? null,
                    'is_active' => $catData['is_active'] ?? true,
                ]);
            } else {
                // 테넌트 카테고리
                $tenantId = $catData['tenant_id'] ?? $this->getTenantId();

                $exists = Category::withoutGlobalScopes()
                    ->where('tenant_id', $tenantId)
                    ->where('code_group', $catData['code_group'])
                    ->where('code', $catData['code'])
                    ->exists();

                if ($exists) {
                    $skipped++;

                    continue;
                }

                // 부모 찾기
                $parentId = null;
                if (! empty($catData['parent_code'])) {
                    $parent = Category::withoutGlobalScopes()
                        ->where('tenant_id', $tenantId)
                        ->where('code_group', $catData['code_group'])
                        ->where('code', $catData['parent_code'])
                        ->first();
                    $parentId = $parent?->id;
                }

                Category::create([
                    'tenant_id' => $tenantId,
                    'parent_id' => $parentId,
                    'code_group' => $catData['code_group'],
                    'code' => $catData['code'],
                    'name' => $catData['name'],
                    'sort_order' => $catData['sort_order'] ?? 0,
                    'description' => $catData['description'] ?? null,
                    'is_active' => $catData['is_active'] ?? true,
                ]);
            }
            $imported++;
        }

        return response()->json([
            'success' => true,
            'message' => "{$imported}개 카테고리가 동기화되었습니다.".($skipped > 0 ? " ({$skipped}개 스킵)" : ''),
            'imported' => $imported,
            'skipped' => $skipped,
        ]);
    }

    /**
     * Push (로컬 → 원격)
     */
    public function push(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'env' => 'required|string|in:dev,prod',
            'type' => 'required|string|in:global,tenant',
            'category_keys' => 'required|array|min:1',
            'category_keys.*' => 'string',
        ]);

        $environments = $this->getEnvironments();
        $env = $environments[$validated['env']] ?? null;

        if (! $env || empty($env['url'])) {
            return response()->json(['error' => '환경 설정이 없습니다.'], 400);
        }

        // 선택된 카테고리 조회 (타입 필터 적용)
        $localCategories = $this->getCategoryList($validated['type']);
        $selectedCategories = array_filter($localCategories, function ($cat) use ($validated) {
            $key = $this->makeCategoryKey($cat);

            return in_array($key, $validated['category_keys']);
        });

        if (empty($selectedCategories)) {
            return response()->json(['error' => '선택된 카테고리가 없습니다.'], 400);
        }

        // 원격 서버로 전송
        try {
            $response = Http::withHeaders([
                'X-Menu-Sync-Key' => $env['api_key'],
                'Accept' => 'application/json',
            ])->post(rtrim($env['url'], '/').'/category-sync/import', [
                'categories' => array_values($selectedCategories),
            ]);

            if ($response->successful()) {
                return response()->json([
                    'success' => true,
                    'message' => $response->json('message', '동기화 완료'),
                    'imported' => $response->json('imported', 0),
                    'skipped' => $response->json('skipped', 0),
                ]);
            }

            return response()->json([
                'error' => $response->json('error', '원격 서버 오류'),
            ], $response->status());
        } catch (\Exception $e) {
            return response()->json(['error' => '연결 실패: '.$e->getMessage()], 500);
        }
    }

    /**
     * Pull (원격 → 로컬)
     */
    public function pull(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'env' => 'required|string|in:dev,prod',
            'type' => 'required|string|in:global,tenant',
            'category_keys' => 'required|array|min:1',
            'category_keys.*' => 'string',
        ]);

        $environments = $this->getEnvironments();
        $env = $environments[$validated['env']] ?? null;

        if (! $env || empty($env['url'])) {
            return response()->json(['error' => '환경 설정이 없습니다.'], 400);
        }

        // 원격 카테고리 조회 (타입 필터 적용)
        try {
            $remoteCategories = $this->fetchRemoteCategories($env, $validated['type']);
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 500);
        }

        // 선택된 카테고리만 필터링
        $selectedCategories = array_filter($remoteCategories, function ($cat) use ($validated) {
            $key = $this->makeCategoryKey($cat);

            return in_array($key, $validated['category_keys']);
        });

        if (empty($selectedCategories)) {
            return response()->json(['error' => '선택된 카테고리를 찾을 수 없습니다.'], 400);
        }

        // 로컬에 Import
        $imported = 0;
        $skipped = 0;

        foreach ($selectedCategories as $catData) {
            if ($catData['is_global']) {
                $exists = GlobalCategory::where('code_group', $catData['code_group'])
                    ->where('code', $catData['code'])
                    ->exists();

                if ($exists) {
                    $skipped++;

                    continue;
                }

                $parentId = null;
                if (! empty($catData['parent_code'])) {
                    $parent = GlobalCategory::where('code_group', $catData['code_group'])
                        ->where('code', $catData['parent_code'])
                        ->first();
                    $parentId = $parent?->id;
                }

                GlobalCategory::create([
                    'parent_id' => $parentId,
                    'code_group' => $catData['code_group'],
                    'code' => $catData['code'],
                    'name' => $catData['name'],
                    'sort_order' => $catData['sort_order'] ?? 0,
                    'description' => $catData['description'] ?? null,
                    'is_active' => $catData['is_active'] ?? true,
                ]);
            } else {
                $tenantId = $this->getTenantId();

                $exists = Category::withoutGlobalScopes()
                    ->where('tenant_id', $tenantId)
                    ->where('code_group', $catData['code_group'])
                    ->where('code', $catData['code'])
                    ->exists();

                if ($exists) {
                    $skipped++;

                    continue;
                }

                $parentId = null;
                if (! empty($catData['parent_code'])) {
                    $parent = Category::withoutGlobalScopes()
                        ->where('tenant_id', $tenantId)
                        ->where('code_group', $catData['code_group'])
                        ->where('code', $catData['parent_code'])
                        ->first();
                    $parentId = $parent?->id;
                }

                Category::create([
                    'tenant_id' => $tenantId,
                    'parent_id' => $parentId,
                    'code_group' => $catData['code_group'],
                    'code' => $catData['code'],
                    'name' => $catData['name'],
                    'sort_order' => $catData['sort_order'] ?? 0,
                    'description' => $catData['description'] ?? null,
                    'is_active' => $catData['is_active'] ?? true,
                ]);
            }
            $imported++;
        }

        return response()->json([
            'success' => true,
            'message' => "{$imported}개 카테고리가 동기화되었습니다.".($skipped > 0 ? " ({$skipped}개 스킵)" : ''),
            'imported' => $imported,
            'skipped' => $skipped,
        ]);
    }

    /**
     * 카테고리 목록 조회
     *
     * @param  string  $type  'global', 'tenant', or 'all'
     */
    private function getCategoryList(string $type = 'all'): array
    {
        $tenantId = $this->getTenantId();
        $categories = [];

        // 글로벌 카테고리
        if ($type === 'global' || $type === 'all') {
            $globalCategories = GlobalCategory::whereNull('deleted_at')
                ->orderBy('code_group')
                ->orderBy('sort_order')
                ->get();

            foreach ($globalCategories as $cat) {
                $parentCode = null;
                if ($cat->parent_id) {
                    $parent = GlobalCategory::find($cat->parent_id);
                    $parentCode = $parent?->code;
                }

                $categories[] = [
                    'is_global' => true,
                    'tenant_id' => null,
                    'code_group' => $cat->code_group,
                    'code' => $cat->code,
                    'name' => $cat->name,
                    'parent_code' => $parentCode,
                    'sort_order' => $cat->sort_order,
                    'description' => $cat->description,
                    'is_active' => $cat->is_active,
                ];
            }
        }

        // 테넌트 카테고리
        if ($type === 'tenant' || $type === 'all') {
            $tenantCategories = Category::withoutGlobalScopes()
                ->where('tenant_id', $tenantId)
                ->whereNull('deleted_at')
                ->orderBy('code_group')
                ->orderBy('sort_order')
                ->get();

            foreach ($tenantCategories as $cat) {
                $parentCode = null;
                if ($cat->parent_id) {
                    $parent = Category::withoutGlobalScopes()->find($cat->parent_id);
                    $parentCode = $parent?->code;
                }

                $categories[] = [
                    'is_global' => false,
                    'tenant_id' => $cat->tenant_id,
                    'code_group' => $cat->code_group,
                    'code' => $cat->code,
                    'name' => $cat->name,
                    'parent_code' => $parentCode,
                    'sort_order' => $cat->sort_order,
                    'description' => $cat->description,
                    'is_active' => $cat->is_active,
                ];
            }
        }

        return $categories;
    }

    /**
     * 원격 카테고리 조회
     */
    private function fetchRemoteCategories(array $env, string $type = 'all'): array
    {
        $response = Http::withHeaders([
            'X-Menu-Sync-Key' => $env['api_key'],
            'Accept' => 'application/json',
        ])->timeout(10)->get(rtrim($env['url'], '/').'/category-sync/export', [
            'type' => $type,
        ]);

        if (! $response->successful()) {
            throw new \Exception('API 오류: HTTP '.$response->status());
        }

        $data = $response->json();
        if (! isset($data['categories'])) {
            throw new \Exception('잘못된 응답 형식');
        }

        $this->remoteTenantName = $data['tenant_name'] ?? null;

        return $data['categories'];
    }

    /**
     * 카테고리 키 생성 (유니크 식별자)
     */
    private function makeCategoryKey(array $cat): string
    {
        $typePart = $cat['is_global'] ? 'global' : "tenant:{$cat['tenant_id']}";

        return "{$typePart}:{$cat['code_group']}:{$cat['code']}";
    }

    /**
     * 차이점 계산
     */
    private function calculateDiff(array $localCategories, array $remoteCategories): array
    {
        $localKeys = array_map(fn ($c) => $this->makeCategoryKey($c), $localCategories);
        $remoteKeys = array_map(fn ($c) => $this->makeCategoryKey($c), $remoteCategories);

        return [
            'local_only' => array_values(array_diff($localKeys, $remoteKeys)),
            'remote_only' => array_values(array_diff($remoteKeys, $localKeys)),
            'both' => array_values(array_intersect($localKeys, $remoteKeys)),
        ];
    }
}
