<?php

namespace App\Services;

use App\Models\Members\User;
use App\Models\Tenants\TenantUserProfile;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class EmployeeService extends Service
{
    /**
     * 사원 목록 조회 (tenant_user_profiles + users 조인)
     */
    public function index(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();

        $query = TenantUserProfile::query()
            ->where('tenant_id', $tenantId)
            ->with(['user', 'department', 'manager', 'rankPosition', 'titlePosition']);

        // 검색 (이름, 이메일, 사원코드)
        if (! empty($params['q'])) {
            $search = $params['q'];
            $query->where(function ($q) use ($search) {
                $q->whereHas('user', function ($uq) use ($search) {
                    $uq->where('name', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%");
                })
                    // json_extra에서 employee_code 검색
                    ->orWhereJsonContains('json_extra->employee_code', $search);
            });
        }

        // 고용 상태 필터 (employee_status)
        if (! empty($params['status'])) {
            $query->where('employee_status', $params['status']);
        }

        // 부서 필터
        if (! empty($params['department_id'])) {
            $query->where('department_id', $params['department_id']);
        }

        // 시스템 계정 보유 여부 필터
        if (isset($params['has_account'])) {
            $hasAccount = filter_var($params['has_account'], FILTER_VALIDATE_BOOLEAN);
            $query->whereHas('user', function ($q) use ($hasAccount) {
                if ($hasAccount) {
                    $q->whereNotNull('password');
                } else {
                    $q->whereNull('password');
                }
            });
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'created_at';
        $sortDir = $params['sort_dir'] ?? 'desc';
        $query->orderBy($sortBy, $sortDir);

        $perPage = $params['per_page'] ?? 20;

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

    /**
     * 사원 상세 조회
     */
    public function show(int $id): TenantUserProfile
    {
        $tenantId = $this->tenantId();

        $profile = TenantUserProfile::query()
            ->where('tenant_id', $tenantId)
            ->with(['user', 'department', 'manager', 'rankPosition', 'titlePosition'])
            ->find($id);

        if (! $profile) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        return $profile;
    }

    /**
     * 사원 등록 (users 테이블에 사용자 생성 + tenant_user_profiles 생성)
     *
     * @param  array  $data  사원 데이터
     *                       - create_account: bool (true=시스템 계정 생성, false=사원 전용)
     *                       - password: string (create_account=true일 때 필수)
     */
    public function store(array $data): TenantUserProfile
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 1. 이메일 중복 체크 (전역 유니크)
        $existingUser = User::withTrashed()->where('email', $data['email'])->first();
        if ($existingUser) {
            throw new \InvalidArgumentException(__('error.email_already_exists'));
        }

        // 2. user_id 중복 체크 및 유니크 ID 생성
        $userIdValue = $data['user_id'] ?? $this->generateUniqueUserId($data['email']);

        return DB::transaction(function () use ($data, $tenantId, $userId, $userIdValue) {
            // 3. 비밀번호 결정: password가 있으면 시스템 계정 생성
            // User 모델에 'password' => 'hashed' 캐스트가 있으므로 Hash::make() 불필요
            $password = ! empty($data['password']) ? $data['password'] : null;

            // 4. users 테이블에 사용자 생성
            $user = User::create([
                'user_id' => $userIdValue,
                'name' => $data['name'],
                'email' => $data['email'],
                'phone' => $data['phone'] ?? null,
                'password' => $password,
                'is_active' => $data['is_active'] ?? true,
                'created_by' => $userId,
            ]);

            // 3. user_tenants pivot에 관계 추가
            $user->tenantsMembership()->attach($tenantId, [
                'is_active' => true,
                'is_default' => true,
                'joined_at' => now(),
            ]);

            // 4. tenant_user_profiles 생성
            $profile = TenantUserProfile::create([
                'tenant_id' => $tenantId,
                'user_id' => $user->id,
                'department_id' => $data['department_id'] ?? null,
                'position_key' => $data['position_key'] ?? null,
                'job_title_key' => $data['job_title_key'] ?? null,
                'work_location_key' => $data['work_location_key'] ?? null,
                'employment_type_key' => $data['employment_type_key'] ?? null,
                'employee_status' => $data['employee_status'] ?? 'active',
                'manager_user_id' => $data['manager_user_id'] ?? null,
                'profile_photo_path' => $data['profile_photo_path'] ?? null,
                'display_name' => $data['display_name'] ?? null,
            ]);

            // 5. json_extra 사원 정보 설정
            $profile->updateEmployeeInfo([
                'employee_code' => $data['employee_code'] ?? null,
                'resident_number' => $data['resident_number'] ?? null,
                'gender' => $data['gender'] ?? null,
                'address' => $data['address'] ?? null,
                'salary' => $data['salary'] ?? null,
                'hire_date' => $data['hire_date'] ?? null,
                'rank' => $data['rank'] ?? null,
                'bank_account' => $data['bank_account'] ?? null,
                'work_type' => $data['work_type'] ?? 'regular',
                'contract_info' => $data['contract_info'] ?? null,
            ]);
            $profile->save();

            return $profile->fresh(['user', 'department', 'manager', 'rankPosition', 'titlePosition']);
        });
    }

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

        $profile = TenantUserProfile::query()
            ->where('tenant_id', $tenantId)
            ->find($id);

        if (! $profile) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        return DB::transaction(function () use ($profile, $data, $userId) {
            // 1. users 테이블 업데이트 (기본 정보)
            $user = $profile->user;
            $userUpdates = [];

            if (isset($data['name'])) {
                $userUpdates['name'] = $data['name'];
            }
            if (isset($data['email'])) {
                $userUpdates['email'] = $data['email'];
            }
            if (isset($data['phone'])) {
                $userUpdates['phone'] = $data['phone'];
            }
            if (isset($data['is_active'])) {
                $userUpdates['is_active'] = $data['is_active'];
            }
            if (! empty($userUpdates)) {
                $userUpdates['updated_by'] = $userId;
                $user->update($userUpdates);
            }

            // 2. tenant_user_profiles 업데이트
            $profileUpdates = [];
            $profileFields = [
                'department_id',
                'position_key',
                'job_title_key',
                'work_location_key',
                'employment_type_key',
                'employee_status',
                'manager_user_id',
                'profile_photo_path',
                'display_name',
            ];

            foreach ($profileFields as $field) {
                if (array_key_exists($field, $data)) {
                    $profileUpdates[$field] = $data[$field];
                }
            }

            if (! empty($profileUpdates)) {
                $profile->update($profileUpdates);
            }

            // 3. json_extra 사원 정보 업데이트
            $jsonExtraFields = [
                'employee_code',
                'resident_number',
                'gender',
                'address',
                'salary',
                'hire_date',
                'rank',
                'bank_account',
                'work_type',
                'contract_info',
            ];

            $jsonExtraUpdates = [];
            foreach ($jsonExtraFields as $field) {
                if (array_key_exists($field, $data)) {
                    $jsonExtraUpdates[$field] = $data[$field];
                }
            }

            if (! empty($jsonExtraUpdates)) {
                $profile->updateEmployeeInfo($jsonExtraUpdates);
                $profile->save();
            }

            return $profile->fresh(['user', 'department', 'manager', 'rankPosition', 'titlePosition']);
        });
    }

    /**
     * 사원 삭제 (soft delete)
     */
    public function destroy(int $id): array
    {
        $tenantId = $this->tenantId();

        $profile = TenantUserProfile::query()
            ->where('tenant_id', $tenantId)
            ->find($id);

        if (! $profile) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        // tenant_user_profiles에는 SoftDeletes가 없으므로 hard delete
        // 또는 employee_status를 resigned로 변경
        $profile->update(['employee_status' => 'resigned']);

        return [
            'id' => $id,
            'deleted_at' => now()->toDateTimeString(),
        ];
    }

    /**
     * 일괄 삭제
     */
    public function bulkDelete(array $ids): array
    {
        $tenantId = $this->tenantId();

        $updated = TenantUserProfile::query()
            ->where('tenant_id', $tenantId)
            ->whereIn('id', $ids)
            ->update(['employee_status' => 'resigned']);

        return [
            'processed' => count($ids),
            'updated' => $updated,
        ];
    }

    /**
     * 사원 통계
     */
    public function stats(): array
    {
        $tenantId = $this->tenantId();

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

        $total = (clone $baseQuery)->count();
        $active = (clone $baseQuery)->where('employee_status', 'active')->count();
        $leave = (clone $baseQuery)->where('employee_status', 'leave')->count();
        $resigned = (clone $baseQuery)->where('employee_status', 'resigned')->count();

        return [
            'total' => $total,
            'active' => $active,
            'leave' => $leave,
            'resigned' => $resigned,
        ];
    }

    /**
     * 시스템 계정 생성 (비밀번호 설정)
     */
    public function createAccount(int $id, string $password): TenantUserProfile
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $profile = TenantUserProfile::query()
            ->where('tenant_id', $tenantId)
            ->with('user')
            ->find($id);

        if (! $profile) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        // User 모델에 'password' => 'hashed' 캐스트가 있으므로 Hash::make() 불필요
        $profile->user->update([
            'password' => $password,
            'must_change_password' => true,
            'updated_by' => $userId,
        ]);

        return $profile->fresh(['user', 'department', 'manager', 'rankPosition', 'titlePosition']);
    }

    /**
     * 시스템 계정 해제 (비밀번호 제거 → 로그인 불가, 사원 정보 유지)
     */
    public function revokeAccount(int $id): TenantUserProfile
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $profile = TenantUserProfile::query()
            ->where('tenant_id', $tenantId)
            ->with('user')
            ->find($id);

        if (! $profile) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        $user = $profile->user;

        // 이미 계정이 없는 경우
        if (empty($user->password)) {
            throw new \InvalidArgumentException(__('employee.no_account'));
        }

        // 1. 비밀번호 제거 (로그인 불가)
        $user->update([
            'password' => null,
            'must_change_password' => false,
            'updated_by' => $userId,
        ]);

        // 2. 기존 토큰 무효화 (로그아웃 처리)
        $user->tokens()->delete();

        return $profile->fresh(['user', 'department', 'manager', 'rankPosition', 'titlePosition']);
    }

    /**
     * 유니크한 사용자 ID 자동 생성
     * 중복 시 최대 10회까지 재시도
     */
    private function generateUniqueUserId(string $email): string
    {
        $prefix = explode('@', $email)[0];
        $prefix = strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $prefix));

        $maxAttempts = 10;
        for ($i = 0; $i < $maxAttempts; $i++) {
            $suffix = Str::random(6); // 4자리 → 6자리로 증가
            $userId = $prefix.'_'.$suffix;

            // 중복 체크 (삭제된 사용자 포함)
            if (! User::withTrashed()->where('user_id', $userId)->exists()) {
                return $userId;
            }
        }

        // 최대 시도 후에도 실패 시 타임스탬프 추가
        return $prefix.'_'.time().'_'.Str::random(4);
    }
}
