<?php

namespace App\Services;

use App\Models\Construction\Contract;
use App\Models\Production\WorkOrder;
use App\Models\Tenants\Leave;
use App\Models\Tenants\Schedule;
use Illuminate\Support\Collection;

/**
 * CEO 대시보드 캘린더 서비스
 *
 * 각 카테고리별 일정을 집계하여 캘린더 데이터 제공
 * - 작업지시(WorkOrder): 생산 일정
 * - 계약(Contract): 시공 일정
 * - 휴가(Leave): 직원 휴가 일정
 * - 일정(Schedule): 본사 공통 일정 + 테넌트 일정 (세금 신고, 공휴일 등)
 */
class CalendarService extends Service
{
    /**
     * 캘린더 일정 조회
     *
     * @param  string  $startDate  조회 시작일 (Y-m-d)
     * @param  string  $endDate  조회 종료일 (Y-m-d)
     * @param  string|null  $type  일정 타입 필터 (schedule|order|construction|other|null=전체)
     * @param  string|null  $departmentFilter  부서 필터 (all|department|personal)
     */
    public function getSchedules(
        string $startDate,
        string $endDate,
        ?string $type = null,
        ?string $departmentFilter = 'all'
    ): array {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $schedules = collect();

        // 타입 필터에 따라 데이터 수집
        if ($type === null || $type === 'order') {
            $schedules = $schedules->merge(
                $this->getWorkOrderSchedules($tenantId, $startDate, $endDate, $departmentFilter, $userId)
            );
        }

        if ($type === null || $type === 'construction') {
            $schedules = $schedules->merge(
                $this->getContractSchedules($tenantId, $startDate, $endDate, $departmentFilter, $userId)
            );
        }

        if ($type === null || $type === 'schedule') {
            $schedules = $schedules->merge(
                $this->getLeaveSchedules($tenantId, $startDate, $endDate, $departmentFilter, $userId)
            );
        }

        // 범용 일정 (본사 공통 + 테넌트 일정): 항상 포함 또는 'other' 필터 시
        if ($type === null || $type === 'other') {
            $schedules = $schedules->merge(
                $this->getGeneralSchedules($tenantId, $startDate, $endDate)
            );
        }

        // startDate 기준 정렬
        $sortedSchedules = $schedules
            ->sortBy('startDate')
            ->values()
            ->toArray();

        return [
            'items' => $sortedSchedules,
            'total_count' => count($sortedSchedules),
        ];
    }

    /**
     * 작업지시(발주) 일정 조회
     */
    private function getWorkOrderSchedules(
        int $tenantId,
        string $startDate,
        string $endDate,
        string $departmentFilter,
        int $userId
    ): Collection {
        $query = WorkOrder::query()
            ->where('tenant_id', $tenantId)
            ->where('is_active', true)
            ->whereNotNull('scheduled_date')
            ->where('scheduled_date', '>=', $startDate)
            ->where('scheduled_date', '<=', $endDate)
            ->with(['assignee:id,name', 'assignee.tenantProfile:id,user_id,department_id', 'assignee.tenantProfile.department:id,name']);

        // 부서 필터 적용
        if ($departmentFilter === 'personal') {
            $query->where('assignee_id', $userId);
        }
        // department 필터는 부서별 필터링 로직 추가 필요 (현재는 전체)

        $workOrders = $query->orderBy('scheduled_date')->limit(100)->get();

        return $workOrders->map(function ($wo) {
            $assigneeName = $wo->assignee?->name;
            $departmentName = $wo->assignee?->tenantProfile?->department?->name;

            return [
                'id' => 'wo_'.$wo->id,
                'title' => $wo->project_name ?? $wo->work_order_no,
                'startDate' => $wo->scheduled_date?->format('Y-m-d'),
                'endDate' => $wo->scheduled_date?->format('Y-m-d'),
                'startTime' => null,
                'endTime' => null,
                'isAllDay' => true,
                'type' => 'order',
                'department' => $departmentName,
                'personName' => $assigneeName,
                'color' => null,
            ];
        });
    }

    /**
     * 계약(시공) 일정 조회
     */
    private function getContractSchedules(
        int $tenantId,
        string $startDate,
        string $endDate,
        string $departmentFilter,
        int $userId
    ): Collection {
        $query = Contract::query()
            ->where('tenant_id', $tenantId)
            ->where('is_active', true)
            ->whereNotNull('contract_start_date')
            ->where(function ($q) use ($startDate, $endDate) {
                // 기간이 겹치는 계약 조회
                $q->where(function ($sub) use ($startDate, $endDate) {
                    $sub->where('contract_start_date', '<=', $endDate)
                        ->where(function ($inner) use ($startDate) {
                            $inner->where('contract_end_date', '>=', $startDate)
                                ->orWhereNull('contract_end_date');
                        });
                });
            })
            ->with(['constructionPm:id,name', 'constructionPm.tenantProfile:id,user_id,department_id', 'constructionPm.tenantProfile.department:id,name']);

        // 부서 필터 적용
        if ($departmentFilter === 'personal') {
            $query->where('construction_pm_id', $userId);
        }

        $contracts = $query->orderBy('contract_start_date')->limit(100)->get();

        return $contracts->map(function ($contract) {
            $pmName = $contract->constructionPm?->name;
            $departmentName = $contract->constructionPm?->tenantProfile?->department?->name;

            return [
                'id' => 'contract_'.$contract->id,
                'title' => $contract->project_name ?? $contract->contract_code,
                'startDate' => $contract->contract_start_date?->format('Y-m-d'),
                'endDate' => $contract->contract_end_date?->format('Y-m-d') ?? $contract->contract_start_date?->format('Y-m-d'),
                'startTime' => null,
                'endTime' => null,
                'isAllDay' => true,
                'type' => 'construction',
                'department' => $departmentName,
                'personName' => $pmName,
                'color' => null,
            ];
        });
    }

    /**
     * 휴가 일정 조회
     */
    private function getLeaveSchedules(
        int $tenantId,
        string $startDate,
        string $endDate,
        string $departmentFilter,
        int $userId
    ): Collection {
        $query = Leave::query()
            ->where('tenant_id', $tenantId)
            ->where('status', 'approved')
            ->where(function ($q) use ($startDate, $endDate) {
                // 기간이 겹치는 휴가 조회
                $q->where('start_date', '<=', $endDate)
                    ->where('end_date', '>=', $startDate);
            })
            ->with(['user:id,name', 'user.tenantProfile:id,user_id,department_id', 'user.tenantProfile.department:id,name']);

        // 부서 필터 적용
        if ($departmentFilter === 'personal') {
            $query->where('user_id', $userId);
        }

        $leaves = $query->orderBy('start_date')->limit(100)->get();

        return $leaves->map(function ($leave) {
            $userName = $leave->user?->name;
            $departmentName = $leave->user?->tenantProfile?->department?->name;
            $leaveType = $leave->type ?? 'leave';
            $title = $userName
                ? __('message.calendar.leave_title', ['name' => $userName])
                : __('message.calendar.leave_default');

            return [
                'id' => 'leave_'.$leave->id,
                'title' => $title,
                'startDate' => $leave->start_date?->format('Y-m-d'),
                'endDate' => $leave->end_date?->format('Y-m-d'),
                'startTime' => null,
                'endTime' => null,
                'isAllDay' => true,
                'type' => 'schedule',
                'department' => $departmentName,
                'personName' => $userName,
                'color' => null,
            ];
        });
    }

    /**
     * 일정 등록
     */
    public function createSchedule(array $data): array
    {
        $schedule = Schedule::create([
            'tenant_id' => $this->tenantId(),
            'title' => $data['title'],
            'description' => $data['description'] ?? null,
            'start_date' => $data['start_date'],
            'end_date' => $data['end_date'],
            'start_time' => $data['start_time'] ?? null,
            'end_time' => $data['end_time'] ?? null,
            'is_all_day' => $data['is_all_day'] ?? true,
            'type' => Schedule::TYPE_EVENT,
            'color' => $data['color'] ?? null,
            'is_active' => true,
            'created_by' => $this->apiUserId(),
        ]);

        return [
            'id' => $schedule->id,
            'title' => $schedule->title,
            'start_date' => $schedule->start_date?->format('Y-m-d'),
            'end_date' => $schedule->end_date?->format('Y-m-d'),
        ];
    }

    /**
     * 일정 수정
     */
    public function updateSchedule(int $id, array $data): array
    {
        $schedule = Schedule::where('tenant_id', $this->tenantId())
            ->findOrFail($id);

        $schedule->update([
            'title' => $data['title'],
            'description' => $data['description'] ?? null,
            'start_date' => $data['start_date'],
            'end_date' => $data['end_date'],
            'start_time' => $data['start_time'] ?? null,
            'end_time' => $data['end_time'] ?? null,
            'is_all_day' => $data['is_all_day'] ?? true,
            'color' => $data['color'] ?? null,
            'updated_by' => $this->apiUserId(),
        ]);

        return [
            'id' => $schedule->id,
            'title' => $schedule->title,
            'start_date' => $schedule->start_date?->format('Y-m-d'),
            'end_date' => $schedule->end_date?->format('Y-m-d'),
        ];
    }

    /**
     * 일정 삭제 (소프트 삭제)
     */
    public function deleteSchedule(int $id): array
    {
        $schedule = Schedule::where('tenant_id', $this->tenantId())
            ->findOrFail($id);

        $schedule->update(['deleted_by' => $this->apiUserId()]);
        $schedule->delete();

        return [
            'id' => $schedule->id,
        ];
    }

    /**
     * 범용 일정 조회 (본사 공통 + 테넌트 일정)
     */
    private function getGeneralSchedules(
        int $tenantId,
        string $startDate,
        string $endDate
    ): Collection {
        $schedules = Schedule::query()
            ->forTenant($tenantId)
            ->active()
            ->betweenDates($startDate, $endDate)
            ->with(['creator:id,name'])
            ->orderBy('start_date')
            ->limit(100)
            ->get();

        return $schedules->map(function ($schedule) {
            return [
                'id' => 'schedule_'.$schedule->id,
                'title' => $schedule->title,
                'startDate' => $schedule->start_date?->format('Y-m-d'),
                'endDate' => $schedule->end_date?->format('Y-m-d') ?? $schedule->start_date?->format('Y-m-d'),
                'startTime' => $schedule->start_time,
                'endTime' => $schedule->end_time,
                'isAllDay' => $schedule->is_all_day,
                'type' => 'other',
                'department' => null,
                'personName' => $schedule->creator?->name,
                'color' => $schedule->color,
            ];
        });
    }
}
