<?php

namespace App\Services;

use App\Models\Tenants\Tenant;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;

class TenantService
{
    public function __construct(
        private readonly ArchiveService $archiveService
    ) {}

    /**
     * 테넌트 목록 조회 (페이지네이션)
     */
    public function getTenants(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = Tenant::query()
            ->withCount(['users', 'departments', 'menus', 'roles'])
            ->withTrashed();

        // 검색 필터
        if (! empty($filters['search'])) {
            $search = $filters['search'];
            $query->where(function ($q) use ($search) {
                $q->where('company_name', 'like', "%{$search}%")
                    ->orWhere('code', 'like', "%{$search}%")
                    ->orWhere('email', 'like', "%{$search}%");
            });
        }

        // 상태 필터
        if (! empty($filters['tenant_st_code'])) {
            $query->where('tenant_st_code', $filters['tenant_st_code']);
        }

        // Soft Delete 필터
        if (isset($filters['trashed'])) {
            if ($filters['trashed'] === 'only') {
                $query->onlyTrashed();
            } elseif ($filters['trashed'] === 'with') {
                $query->withTrashed();
            }
        }

        // 정렬
        $sortBy = $filters['sort_by'] ?? 'id';
        $sortDirection = $filters['sort_direction'] ?? 'desc';
        $query->orderBy($sortBy, $sortDirection);

        return $query->paginate($perPage);
    }

    /**
     * 특정 테넌트 조회
     */
    public function getTenantById(int $id, bool $withTrashed = false): ?Tenant
    {
        $query = Tenant::query()->withCount(['users', 'departments', 'menus', 'roles']);

        if ($withTrashed) {
            $query->withTrashed();
        }

        return $query->find($id);
    }

    /**
     * 테넌트 생성
     */
    public function createTenant(array $data): Tenant
    {
        return Tenant::create($data);
    }

    /**
     * 테넌트 수정
     */
    public function updateTenant(int $id, array $data): bool
    {
        $tenant = Tenant::findOrFail($id);

        return $tenant->update($data);
    }

    /**
     * 테넌트 삭제 (Soft Delete)
     */
    public function deleteTenant(int $id): bool
    {
        $tenant = Tenant::findOrFail($id);

        // 삭제자 기록
        $tenant->deleted_by = auth()->id();
        $tenant->save();

        return $tenant->delete();
    }

    /**
     * 테넌트 복원
     */
    public function restoreTenant(int $id): bool
    {
        $tenant = Tenant::onlyTrashed()->findOrFail($id);

        // 삭제 정보 초기화
        $tenant->deleted_by = null;

        return $tenant->restore();
    }

    /**
     * 테넌트 영구 삭제 (슈퍼관리자 전용)
     *
     * 1. 테넌트와 관련 데이터를 아카이브에 저장
     * 2. 관련 데이터 삭제
     * 3. 테넌트 영구 삭제
     */
    public function forceDeleteTenant(int $id): bool
    {
        $tenant = Tenant::withTrashed()->findOrFail($id);

        return DB::transaction(function () use ($tenant) {
            // 1. 아카이브에 저장 (복원 가능하도록)
            $this->archiveService->archiveTenantWithRelations($tenant);

            // 2. FK 체크 비활성화 후 관련 데이터 삭제
            DB::statement('SET FOREIGN_KEY_CHECKS=0');

            try {
                $tenant->users()->detach(); // user_tenants 관계 삭제

                // 역할 하위 참조 데이터 정리
                $roleIds = $tenant->roles()->pluck('id');
                if ($roleIds->isNotEmpty()) {
                    DB::table('user_roles')->whereIn('role_id', $roleIds)->delete();
                    DB::table('role_menu_permissions')->whereIn('role_id', $roleIds)->delete();
                    DB::table('role_has_permissions')->whereIn('role_id', $roleIds)->delete();
                }

                $tenant->departments()->forceDelete();
                $tenant->menus()->forceDelete();
                $tenant->roles()->forceDelete();

                // 3. 테넌트 영구 삭제
                $result = $tenant->forceDelete();
            } finally {
                DB::statement('SET FOREIGN_KEY_CHECKS=1');
            }

            return $result;
        });
    }

    /**
     * 활성 테넌트 목록 (드롭다운용)
     */
    public function getActiveTenants(): Collection
    {
        return Tenant::query()
            ->active()
            ->orderBy('company_name')
            ->get(['id', 'company_name', 'code']);
    }

    /**
     * 테넌트 코드 중복 체크
     */
    public function isCodeExists(string $code, ?int $excludeId = null): bool
    {
        $query = Tenant::where('code', $code);

        if ($excludeId) {
            $query->where('id', '!=', $excludeId);
        }

        return $query->exists();
    }

    /**
     * 테넌트 통계
     */
    public function getTenantStats(): array
    {
        return [
            'total' => Tenant::count(),
            'active' => Tenant::where('tenant_st_code', 'active')->count(),
            'trial' => Tenant::where('tenant_st_code', 'trial')->count(),
            'suspended' => Tenant::where('tenant_st_code', 'suspended')->count(),
            'expired' => Tenant::where('tenant_st_code', 'expired')->count(),
            'trashed' => Tenant::onlyTrashed()->count(),
        ];
    }

    /**
     * 모달용 테넌트 상세 정보 조회
     */
    public function getTenantForModal(int $id): ?Tenant
    {
        return Tenant::query()
            ->with('deletedByUser')
            ->withCount(['users', 'departments', 'menus', 'roles'])
            ->withTrashed()
            ->find($id);
    }

    /**
     * 테넌트 소속 사용자 목록 조회
     */
    public function getTenantUsers(int $tenantId): Collection
    {
        $tenant = Tenant::find($tenantId);
        if (! $tenant) {
            return collect();
        }

        // 사용자와 함께 역할/부서 정보를 가져옴
        return $tenant->users()
            ->with(['userRoles' => function ($query) use ($tenantId) {
                $query->where('tenant_id', $tenantId)->with('role');
            }, 'departmentUsers' => function ($query) use ($tenantId) {
                $query->where('tenant_id', $tenantId)->with('department');
            }])
            ->orderBy('name')
            ->get()
            ->map(function ($user) {
                // 역할과 부서를 플랫하게 매핑
                $user->roles = $user->userRoles->pluck('role')->filter();
                $user->department = $user->departmentUsers->first()?->department;

                return $user;
            });
    }

    /**
     * 테넌트 부서 목록 조회 (계층 구조)
     */
    public function getTenantDepartments(int $tenantId): Collection
    {
        // Department 모델의 users() 관계가 잘못된 네임스페이스를 참조하므로 직접 카운트
        $departments = \App\Models\Department::query()
            ->where('tenant_id', $tenantId)
            ->orderBy('sort_order')
            ->orderBy('name')
            ->get();

        // 부서별 사용자 수 직접 카운트
        $userCounts = DB::table('department_user')
            ->whereIn('department_id', $departments->pluck('id'))
            ->selectRaw('department_id, count(*) as cnt')
            ->groupBy('department_id')
            ->pluck('cnt', 'department_id');

        return $departments->map(function ($dept) use ($userCounts, $departments) {
            // 사용자 수 설정
            $dept->users_count = $userCounts[$dept->id] ?? 0;

            // 계층 깊이 계산
            $depth = 0;
            $parentId = $dept->parent_id;
            while ($parentId) {
                $depth++;
                $parent = $departments->firstWhere('id', $parentId);
                $parentId = $parent?->parent_id;
            }
            $dept->depth = $depth;

            // 상위 부서 이름
            $dept->parent = $departments->firstWhere('id', $dept->parent_id);

            return $dept;
        });
    }

    /**
     * 테넌트 역할 목록 조회
     */
    public function getTenantRoles(int $tenantId): Collection
    {
        // Role 모델의 userRoles() 관계가 잘못된 네임스페이스를 참조하므로 직접 카운트
        $roles = \App\Models\Role::query()
            ->where('tenant_id', $tenantId)
            ->withCount('permissions')
            ->with('permissions')
            ->orderBy('name')
            ->get();

        // 역할별 사용자 수 직접 카운트
        $userCounts = DB::table('user_roles')
            ->whereIn('role_id', $roles->pluck('id'))
            ->selectRaw('role_id, count(*) as cnt')
            ->groupBy('role_id')
            ->pluck('cnt', 'role_id');

        return $roles->map(function ($role) use ($userCounts) {
            $role->users_count = $userCounts[$role->id] ?? 0;

            return $role;
        });
    }

    /**
     * 테넌트 메뉴 목록 조회 (계층 구조 - 트리 정렬)
     */
    public function getTenantMenus(int $tenantId): \Illuminate\Support\Collection
    {
        $menus = \App\Models\Commons\Menu::query()
            ->where('tenant_id', $tenantId)
            ->orderBy('sort_order')
            ->orderBy('id')
            ->get();

        // 트리 구조로 정렬 후 플랫한 배열로 변환
        return $this->flattenMenuTree($menus);
    }

    /**
     * 트리 구조를 플랫한 배열로 변환 (depth 정보 포함)
     */
    private function flattenMenuTree(Collection $menus, ?int $parentId = null, int $depth = 0): \Illuminate\Support\Collection
    {
        $result = collect();

        $filteredMenus = $menus->where('parent_id', $parentId)->sortBy('sort_order');

        foreach ($filteredMenus as $menu) {
            $menu->depth = $depth;

            // 자식 메뉴 존재 여부 확인
            $menu->has_children = $menus->where('parent_id', $menu->id)->count() > 0;

            $result->push($menu);

            // 자식 메뉴 재귀적으로 추가
            $children = $this->flattenMenuTree($menus, $menu->id, $depth + 1);
            $result = $result->merge($children);
        }

        return $result;
    }

    /**
     * 테넌트 구독 정보 조회
     */
    public function getTenantSubscription(int $tenantId): object
    {
        $tenant = Tenant::find($tenantId);

        // 기본 구독 정보 (실제 구현 시 별도 테이블에서 조회)
        return (object) [
            'plan_name' => $tenant?->subscription_plan ?? '기본 플랜',
            'status' => $tenant?->subscription_status ?? 'active',
            'started_at' => $tenant?->created_at?->format('Y-m-d'),
            'expires_at' => $tenant?->subscription_expires_at ?? null,
            'next_billing_date' => null,
            'max_users' => $tenant?->max_users ?? null,
            'max_storage' => $tenant?->max_storage ?? null,
            'max_storage_mb' => null,
            'has_api_access' => true,
            'has_advanced_reports' => false,
            'features' => [
                ['name' => '기본 기능', 'enabled' => true],
                ['name' => '사용자 관리', 'enabled' => true],
                ['name' => '부서 관리', 'enabled' => true],
                ['name' => '역할 관리', 'enabled' => true],
                ['name' => 'API 접근', 'enabled' => true],
                ['name' => '고급 보고서', 'enabled' => false],
            ],
        ];
    }

    /**
     * 테넌트 사용량 정보 조회
     */
    public function getTenantUsage(int $tenantId): object
    {
        $tenant = Tenant::withCount('users')->find($tenantId);

        return (object) [
            'users_count' => $tenant?->users_count ?? 0,
            'storage_used' => '0 MB',
            'storage_used_mb' => 0,
        ];
    }
}
