<?php

namespace App\Http\Controllers\Api\Admin\HR;

use App\Http\Controllers\Controller;
use App\Models\Boards\File;
use App\Services\GoogleCloudStorageService;
use App\Services\HR\EmployeeService;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\StreamedResponse;

class EmployeeController extends Controller
{
    public function __construct(
        private EmployeeService $employeeService
    ) {}

    /**
     * 사원 목록 조회 (HTMX → HTML / 일반 → JSON)
     */
    public function index(Request $request): JsonResponse|Response
    {
        $employees = $this->employeeService->getEmployees(
            $request->all(),
            $request->integer('per_page', 20)
        );

        if ($request->header('HX-Request')) {
            return response(view('hr.employees.partials.table', compact('employees')));
        }

        return response()->json([
            'success' => true,
            'data' => $employees->items(),
            'meta' => [
                'current_page' => $employees->currentPage(),
                'last_page' => $employees->lastPage(),
                'per_page' => $employees->perPage(),
                'total' => $employees->total(),
            ],
        ]);
    }

    /**
     * 기존 사용자 검색 (사원 미등록, 테넌트 소속)
     */
    public function searchUsers(Request $request): JsonResponse
    {
        $users = $this->employeeService->searchTenantUsers($request->get('q') ?? '');

        return response()->json([
            'success' => true,
            'data' => $users,
        ]);
    }

    /**
     * 사원 통계
     */
    public function stats(): JsonResponse
    {
        $stats = $this->employeeService->getStats();

        return response()->json([
            'success' => true,
            'data' => $stats,
        ]);
    }

    /**
     * 사원 등록
     */
    public function store(Request $request): JsonResponse
    {
        $rules = [
            'existing_user_id' => 'nullable|integer|exists:users,id',
            'name' => 'required|string|max:50',
            'email' => 'nullable|email|max:100',
            'phone' => 'nullable|string|max:20',
            'department_id' => 'nullable|integer|exists:departments,id',
            'position_key' => 'nullable|string|max:50',
            'job_title_key' => 'nullable|string|max:50',
            'work_location_key' => 'nullable|string|max:50',
            'employment_type_key' => 'nullable|string|max:50',
            'employee_status' => 'nullable|string|in:active,leave,resigned',
            'manager_user_id' => 'nullable|integer|exists:users,id',
            'display_name' => 'nullable|string|max:50',
            'hire_date' => 'nullable|date',
            'resign_date' => 'nullable|date',
            'address' => 'nullable|string|max:200',
            'emergency_contact' => 'nullable|string|max:100',
            'resident_number' => 'nullable|string|max:14',
            'bank_account.bank_code' => 'nullable|string|max:20',
            'bank_account.bank_name' => 'nullable|string|max:50',
            'bank_account.account_holder' => 'nullable|string|max:50',
            'bank_account.account_number' => 'nullable|string|max:30',
            'dependents' => 'nullable|array',
            'dependents.*.name' => 'required_with:dependents|string|max:50',
            'dependents.*.nationality' => 'nullable|string|in:korean,foreigner',
            'dependents.*.resident_number' => 'nullable|string|max:14',
            'dependents.*.relationship' => 'nullable|string|max:20',
            'dependents.*.is_disabled' => 'nullable|boolean',
            'dependents.*.is_dependent' => 'nullable|boolean',
        ];

        // 신규 사용자일 때만 이메일 unique 검증
        if (! $request->filled('existing_user_id')) {
            $rules['email'] = 'nullable|email|max:100|unique:users,email';
        }

        $validated = $request->validate($rules);

        try {
            $employee = $this->employeeService->createEmployee($validated);

            return response()->json([
                'success' => true,
                'message' => '사원이 등록되었습니다.',
                'data' => $employee,
            ], 201);
        } catch (\Throwable $e) {
            report($e);

            return response()->json([
                'success' => false,
                'message' => '사원 등록 중 오류가 발생했습니다.',
                'error' => config('app.debug') ? $e->getMessage() : null,
            ], 500);
        }
    }

    /**
     * 사원 상세 조회
     */
    public function show(int $id): JsonResponse
    {
        $employee = $this->employeeService->getEmployeeById($id);

        if (! $employee) {
            return response()->json([
                'success' => false,
                'message' => '사원 정보를 찾을 수 없습니다.',
            ], 404);
        }

        return response()->json([
            'success' => true,
            'data' => $employee,
        ]);
    }

    /**
     * 사원 수정
     */
    public function update(Request $request, int $id): JsonResponse
    {
        $validated = $request->validate([
            'name' => 'sometimes|required|string|max:50',
            'email' => 'nullable|email|max:100',
            'phone' => 'nullable|string|max:20',
            'department_id' => 'nullable|integer|exists:departments,id',
            'position_key' => 'nullable|string|max:50',
            'job_title_key' => 'nullable|string|max:50',
            'work_location_key' => 'nullable|string|max:50',
            'employment_type_key' => 'nullable|string|max:50',
            'employee_status' => 'nullable|string|in:active,leave,resigned',
            'manager_user_id' => 'nullable|integer|exists:users,id',
            'display_name' => 'nullable|string|max:50',
            'hire_date' => 'nullable|date',
            'resign_date' => 'nullable|date',
            'address' => 'nullable|string|max:200',
            'emergency_contact' => 'nullable|string|max:100',
            'resident_number' => 'nullable|string|max:14',
            'bank_account.bank_code' => 'nullable|string|max:20',
            'bank_account.bank_name' => 'nullable|string|max:50',
            'bank_account.account_holder' => 'nullable|string|max:50',
            'bank_account.account_number' => 'nullable|string|max:30',
            'dependents' => 'nullable|array',
            'dependents.*.name' => 'required_with:dependents|string|max:50',
            'dependents.*.nationality' => 'nullable|string|in:korean,foreigner',
            'dependents.*.resident_number' => 'nullable|string|max:14',
            'dependents.*.relationship' => 'nullable|string|max:20',
            'dependents.*.is_disabled' => 'nullable|boolean',
            'dependents.*.is_dependent' => 'nullable|boolean',
        ]);

        try {
            $employee = $this->employeeService->updateEmployee($id, $validated);

            if (! $employee) {
                return response()->json([
                    'success' => false,
                    'message' => '사원 정보를 찾을 수 없습니다.',
                ], 404);
            }

            return response()->json([
                'success' => true,
                'message' => '사원 정보가 수정되었습니다.',
                'data' => $employee,
            ]);
        } catch (\Throwable $e) {
            report($e);

            return response()->json([
                'success' => false,
                'message' => '사원 수정 중 오류가 발생했습니다.',
                'error' => config('app.debug') ? $e->getMessage() : null,
            ], 500);
        }
    }

    /**
     * 사원 삭제 (퇴직 처리)
     */
    public function destroy(Request $request, int $id): JsonResponse|Response
    {
        try {
            $result = $this->employeeService->deleteEmployee($id);

            if (! $result) {
                if ($request->header('HX-Request')) {
                    return response()->json([
                        'success' => false,
                        'message' => '사원 정보를 찾을 수 없습니다.',
                    ], 404);
                }

                return response()->json([
                    'success' => false,
                    'message' => '사원 정보를 찾을 수 없습니다.',
                ], 404);
            }

            if ($request->header('HX-Request')) {
                $employees = $this->employeeService->getEmployees($request->all(), $request->integer('per_page', 20));

                return response(view('hr.employees.partials.table', compact('employees')));
            }

            return response()->json([
                'success' => true,
                'message' => '퇴직 처리되었습니다.',
            ]);
        } catch (\Throwable $e) {
            report($e);

            return response()->json([
                'success' => false,
                'message' => '퇴직 처리 중 오류가 발생했습니다.',
                'error' => config('app.debug') ? $e->getMessage() : null,
            ], 500);
        }
    }

    /**
     * 사원 첨부파일 업로드 (로컬 + GCS 듀얼 저장)
     */
    public function uploadFile(Request $request, int $id, GoogleCloudStorageService $gcs): JsonResponse
    {
        $employee = $this->employeeService->getEmployeeById($id);
        if (! $employee) {
            return response()->json(['success' => false, 'message' => '사원 정보를 찾을 수 없습니다.'], 404);
        }

        $request->validate([
            'files' => 'required|array|max:10',
            'files.*' => 'file|max:20480',
        ]);

        $tenantId = session('selected_tenant_id');
        $uploaded = [];

        foreach ($request->file('files') as $file) {
            $storedName = Str::random(40).'.'.$file->getClientOriginalExtension();
            $storagePath = "employees/{$tenantId}/{$employee->id}/{$storedName}";

            // 로컬 저장
            Storage::disk('tenant')->put($storagePath, file_get_contents($file));

            // GCS 업로드
            $gcsUri = null;
            $gcsObjectName = null;
            if ($gcs->isAvailable()) {
                $gcsObjectName = $storagePath;
                $gcsUri = $gcs->upload($file->getRealPath(), $gcsObjectName);
            }

            $fileRecord = File::create([
                'tenant_id' => $tenantId,
                'document_id' => $employee->id,
                'document_type' => 'employee_profile',
                'original_name' => $file->getClientOriginalName(),
                'stored_name' => $storedName,
                'file_path' => $storagePath,
                'mime_type' => $file->getMimeType(),
                'file_size' => $file->getSize(),
                'file_type' => strtolower($file->getClientOriginalExtension()),
                'gcs_object_name' => $gcsObjectName,
                'gcs_uri' => $gcsUri,
                'uploaded_by' => auth()->id(),
                'created_by' => auth()->id(),
            ]);

            $uploaded[] = $fileRecord;
        }

        return response()->json([
            'success' => true,
            'message' => count($uploaded).'개 파일이 업로드되었습니다.',
            'data' => $uploaded,
        ], 201);
    }

    /**
     * 사원 첨부파일 삭제 (GCS + 로컬 모두 삭제)
     */
    public function deleteFile(int $id, int $fileId, GoogleCloudStorageService $gcs): JsonResponse
    {
        $tenantId = session('selected_tenant_id');

        $file = File::where('id', $fileId)
            ->where('document_id', $id)
            ->where('document_type', 'employee_profile')
            ->where('tenant_id', $tenantId)
            ->first();

        if (! $file) {
            return response()->json(['success' => false, 'message' => '파일을 찾을 수 없습니다.'], 404);
        }

        // GCS 삭제
        if ($gcs->isAvailable() && $file->gcs_object_name) {
            $gcs->delete($file->gcs_object_name);
        }

        // 로컬 삭제
        if ($file->file_path && Storage::disk('tenant')->exists($file->file_path)) {
            Storage::disk('tenant')->delete($file->file_path);
        }

        $file->deleted_by = auth()->id();
        $file->save();
        $file->delete();

        return response()->json(['success' => true, 'message' => '파일이 삭제되었습니다.']);
    }

    /**
     * 사원 첨부파일 다운로드 (GCS Signed URL 우선, 로컬 폴백)
     */
    public function downloadFile(int $id, int $fileId, GoogleCloudStorageService $gcs)
    {
        $tenantId = session('selected_tenant_id');

        $file = File::where('id', $fileId)
            ->where('document_id', $id)
            ->where('document_type', 'employee_profile')
            ->where('tenant_id', $tenantId)
            ->first();

        if (! $file) {
            abort(404, '파일을 찾을 수 없습니다.');
        }

        // GCS Signed URL로 리다이렉트
        if ($gcs->isAvailable() && $file->gcs_object_name) {
            $signedUrl = $gcs->getSignedUrl($file->gcs_object_name, 60);
            if ($signedUrl) {
                return redirect($signedUrl);
            }
        }

        // 로컬 폴백
        $disk = Storage::disk('tenant');
        if ($file->file_path && $disk->exists($file->file_path)) {
            return $disk->download($file->file_path, $file->original_name);
        }

        abort(404, '파일이 서버에 존재하지 않습니다.');
    }

    /**
     * 입퇴사자 현황 목록 (HTMX → HTML / 일반 → JSON)
     */
    public function tenure(Request $request): JsonResponse|Response
    {
        $employees = $this->employeeService->getEmployeeTenure(
            $request->all(),
            $request->integer('per_page', 50)
        );

        // 근속기간 계산 추가
        $employees->getCollection()->each(function ($employee) {
            $hireDate = $employee->hire_date;
            if ($hireDate) {
                $hire = Carbon::parse($hireDate);
                $end = $employee->resign_date ? Carbon::parse($employee->resign_date) : today();
                $tenureDays = $hire->diffInDays($end);
                $diff = $hire->diff($end);

                $employee->tenure_days = $tenureDays;
                $employee->tenure_label = $this->formatTenureLabel($diff);
            } else {
                $employee->tenure_days = 0;
                $employee->tenure_label = '-';
            }
        });

        if ($request->header('HX-Request')) {
            $stats = $this->employeeService->getTenureStats();

            return response(view('hr.employee-tenure.partials.table', compact('employees', 'stats')));
        }

        return response()->json([
            'success' => true,
            'data' => $employees->items(),
            'meta' => [
                'current_page' => $employees->currentPage(),
                'last_page' => $employees->lastPage(),
                'per_page' => $employees->perPage(),
                'total' => $employees->total(),
            ],
        ]);
    }

    /**
     * 입퇴사자 현황 CSV 내보내기
     */
    public function tenureExport(Request $request): StreamedResponse
    {
        $employees = $this->employeeService->getTenureExportData($request->all());

        $filename = '입퇴사자현황_'.now()->format('Ymd').'.csv';

        return response()->streamDownload(function () use ($employees) {
            $handle = fopen('php://output', 'w');

            // BOM for Excel UTF-8
            fwrite($handle, "\xEF\xBB\xBF");

            // 헤더
            fputcsv($handle, ['No.', '사원명', '부서', '직책', '상태', '입사일', '퇴사일', '근속기간', '근속일수']);

            $index = 1;
            foreach ($employees as $employee) {
                $hireDate = $employee->hire_date;
                $tenureDays = 0;
                $tenureLabel = '-';

                if ($hireDate) {
                    $hire = Carbon::parse($hireDate);
                    $end = $employee->resign_date ? Carbon::parse($employee->resign_date) : today();
                    $tenureDays = $hire->diffInDays($end);
                    $tenureLabel = $this->formatTenureLabel($hire->diff($end));
                }

                $statusMap = ['active' => '재직', 'leave' => '휴직', 'resigned' => '퇴직'];

                fputcsv($handle, [
                    $index++,
                    $employee->display_name ?? $employee->user?->name ?? '-',
                    $employee->department?->name ?? '-',
                    $employee->position_label ?? '-',
                    $statusMap[$employee->employee_status] ?? $employee->employee_status,
                    $employee->hire_date ?? '-',
                    $employee->resign_date ?? '-',
                    $tenureLabel,
                    $tenureDays,
                ]);
            }

            fclose($handle);
        }, $filename, [
            'Content-Type' => 'text/csv; charset=UTF-8',
        ]);
    }

    private function formatTenureLabel(\DateInterval $diff): string
    {
        $parts = [];
        if ($diff->y > 0) {
            $parts[] = "{$diff->y}년";
        }
        if ($diff->m > 0) {
            $parts[] = "{$diff->m}개월";
        }
        if ($diff->d > 0 || empty($parts)) {
            $parts[] = "{$diff->d}일";
        }

        return implode(' ', $parts);
    }

    /**
     * 직급/직책 추가
     */
    public function storePosition(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'type' => 'required|string|in:rank,title',
            'name' => 'required|string|max:50',
        ]);

        $position = $this->employeeService->createPosition($validated['type'], $validated['name']);

        return response()->json([
            'success' => true,
            'message' => ($validated['type'] === 'rank' ? '직급' : '직책').'이 추가되었습니다.',
            'data' => [
                'id' => $position->id,
                'key' => $position->key,
                'name' => $position->name,
            ],
        ], 201);
    }
}
