<?php

namespace App\Services\HR;

use App\Models\HR\Attendance;
use App\Models\HR\AttendanceRequest;
use Carbon\CarbonPeriod;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

class AttendanceRequestService
{
    /**
     * 신청 목록 조회
     */
    public function getRequests(array $filters = [], int $perPage = 20): LengthAwarePaginator
    {
        $tenantId = session('selected_tenant_id');

        $query = AttendanceRequest::query()
            ->with(['user', 'user.tenantProfiles' => fn ($q) => $q->where('tenant_id', $tenantId), 'user.tenantProfiles.department', 'approver'])
            ->forTenant($tenantId)
            ->orderByRaw("FIELD(status, 'pending', 'approved', 'rejected')")
            ->orderBy('created_at', 'desc');

        if (! empty($filters['status'])) {
            $query->where('status', $filters['status']);
        }

        if (! empty($filters['user_id'])) {
            $query->where('user_id', $filters['user_id']);
        }

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

    /**
     * 신청 등록
     */
    public function storeRequest(array $data): AttendanceRequest
    {
        $tenantId = session('selected_tenant_id');

        return AttendanceRequest::create([
            'tenant_id' => $tenantId,
            'user_id' => $data['user_id'],
            'request_type' => $data['request_type'],
            'start_date' => $data['start_date'],
            'end_date' => $data['end_date'],
            'reason' => $data['reason'] ?? null,
            'status' => 'pending',
            'json_details' => $data['json_details'] ?? null,
        ]);
    }

    /**
     * 승인 처리
     */
    public function approve(int $id): ?AttendanceRequest
    {
        $tenantId = session('selected_tenant_id');

        $request = AttendanceRequest::query()
            ->forTenant($tenantId)
            ->where('status', 'pending')
            ->find($id);

        if (! $request) {
            return null;
        }

        return DB::transaction(function () use ($request, $tenantId) {
            $request->update([
                'status' => 'approved',
                'approved_by' => auth()->id(),
                'approved_at' => now(),
            ]);

            // 승인 시 해당 기간의 근태 레코드 자동 생성
            $this->createAttendanceRecords($request, $tenantId);

            return $request->fresh(['user', 'approver']);
        });
    }

    /**
     * 반려 처리
     */
    public function reject(int $id, ?string $reason = null): ?AttendanceRequest
    {
        $tenantId = session('selected_tenant_id');

        $request = AttendanceRequest::query()
            ->forTenant($tenantId)
            ->where('status', 'pending')
            ->find($id);

        if (! $request) {
            return null;
        }

        $request->update([
            'status' => 'rejected',
            'approved_by' => auth()->id(),
            'approved_at' => now(),
            'reject_reason' => $reason,
        ]);

        return $request->fresh(['user', 'approver']);
    }

    /**
     * 승인 후 근태 레코드 자동 생성
     */
    private function createAttendanceRecords(AttendanceRequest $request, int $tenantId): void
    {
        $statusMap = [
            'vacation' => 'vacation',
            'businessTrip' => 'businessTrip',
            'remote' => 'remote',
            'fieldWork' => 'fieldWork',
        ];

        $status = $statusMap[$request->request_type] ?? $request->request_type;

        $period = CarbonPeriod::create($request->start_date, $request->end_date);

        foreach ($period as $date) {
            // 주말 제외
            if ($date->isWeekend()) {
                continue;
            }

            Attendance::updateOrCreate(
                [
                    'tenant_id' => $tenantId,
                    'user_id' => $request->user_id,
                    'base_date' => $date->toDateString(),
                ],
                [
                    'status' => $status,
                    'remarks' => $request->reason ? mb_substr($request->reason, 0, 100) : null,
                    'updated_by' => auth()->id(),
                ]
            );
        }
    }
}
