<?php

namespace App\Services\ProjectManagement;

use App\Models\Admin\AdminPmTask;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;

class TaskService
{
    /**
     * 작업 목록 조회 (페이지네이션)
     */
    public function getTasks(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = AdminPmTask::query()
            ->with(['project', 'assignee', 'issues'])
            ->withCount('issues')
            ->withTrashed();

        // 프로젝트 필터
        if (! empty($filters['project_id'])) {
            $query->where('project_id', $filters['project_id']);
        }

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

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

        // 우선순위 필터
        if (! empty($filters['priority'])) {
            $query->where('priority', $filters['priority']);
        }

        // 담당자 필터
        if (! empty($filters['assignee_id'])) {
            $query->where('assignee_id', $filters['assignee_id']);
        }

        // 마감 상태 필터
        if (! empty($filters['due_status'])) {
            if ($filters['due_status'] === 'overdue') {
                $query->overdue();
            } elseif ($filters['due_status'] === 'due_soon') {
                $query->dueSoon();
            }
        }

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

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

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

    /**
     * 프로젝트별 작업 목록 (칸반보드용)
     */
    public function getTasksByProject(int $projectId): Collection
    {
        return AdminPmTask::query()
            ->where('project_id', $projectId)
            ->with(['assignee', 'issues'])
            ->withCount([
                'issues',
                'issues as resolved_issues_count' => function ($query) {
                    $query->whereIn('status', ['resolved', 'closed']);
                },
            ])
            ->orderBy('sort_order')
            ->orderBy('id')
            ->get();
    }

    /**
     * 특정 작업 조회
     */
    public function getTaskById(int $id, bool $withTrashed = false): ?AdminPmTask
    {
        $query = AdminPmTask::query()
            ->with(['project', 'assignee', 'issues', 'creator', 'updater'])
            ->withCount('issues');

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

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

    /**
     * 작업 생성
     */
    public function createTask(array $data): AdminPmTask
    {
        // 정렬 순서 자동 설정
        if (! isset($data['sort_order'])) {
            $maxOrder = AdminPmTask::where('project_id', $data['project_id'])->max('sort_order') ?? 0;
            $data['sort_order'] = $maxOrder + 1;
        }

        $data['created_by'] = auth()->id();

        return AdminPmTask::create($data);
    }

    /**
     * 작업 수정
     */
    public function updateTask(int $id, array $data): bool
    {
        $task = AdminPmTask::findOrFail($id);

        $data['updated_by'] = auth()->id();

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

    /**
     * 작업 삭제 (Soft Delete)
     */
    public function deleteTask(int $id): bool
    {
        $task = AdminPmTask::findOrFail($id);

        $task->deleted_by = auth()->id();
        $task->save();

        return $task->delete();
    }

    /**
     * 작업 복원
     */
    public function restoreTask(int $id): bool
    {
        $task = AdminPmTask::onlyTrashed()->findOrFail($id);

        $task->deleted_by = null;

        return $task->restore();
    }

    /**
     * 작업 영구 삭제
     */
    public function forceDeleteTask(int $id): bool
    {
        return AdminPmTask::withTrashed()->findOrFail($id)->forceDelete();
    }

    /**
     * 작업 상태 변경
     */
    public function changeStatus(int $id, string $status): AdminPmTask
    {
        $task = AdminPmTask::findOrFail($id);

        $task->status = $status;
        $task->updated_by = auth()->id();
        $task->save();

        return $task;
    }

    /**
     * 작업 긴급 토글
     */
    public function toggleUrgent(int $id): AdminPmTask
    {
        $task = AdminPmTask::findOrFail($id);

        $task->is_urgent = ! $task->is_urgent;
        $task->updated_by = auth()->id();
        $task->save();

        return $task;
    }

    /**
     * 작업 순서 변경 (드래그앤드롭)
     */
    public function reorderTasks(int $projectId, array $taskIds): bool
    {
        return DB::transaction(function () use ($projectId, $taskIds) {
            foreach ($taskIds as $order => $taskId) {
                AdminPmTask::where('id', $taskId)
                    ->where('project_id', $projectId)
                    ->update(['sort_order' => $order + 1]);
            }

            return true;
        });
    }

    /**
     * 다중 작업 상태 일괄 변경
     */
    public function bulkChangeStatus(array $taskIds, string $status): int
    {
        return AdminPmTask::whereIn('id', $taskIds)
            ->update([
                'status' => $status,
                'updated_by' => auth()->id(),
                'updated_at' => now(),
            ]);
    }

    /**
     * 다중 작업 담당자 일괄 변경
     */
    public function bulkChangeAssignee(array $taskIds, ?int $assigneeId): int
    {
        return AdminPmTask::whereIn('id', $taskIds)
            ->update([
                'assignee_id' => $assigneeId,
                'updated_by' => auth()->id(),
                'updated_at' => now(),
            ]);
    }

    /**
     * 다중 작업 우선순위 일괄 변경
     */
    public function bulkChangePriority(array $taskIds, string $priority): int
    {
        return AdminPmTask::whereIn('id', $taskIds)
            ->update([
                'priority' => $priority,
                'updated_by' => auth()->id(),
                'updated_at' => now(),
            ]);
    }

    /**
     * 다중 작업 일괄 삭제
     */
    public function bulkDelete(array $taskIds): int
    {
        AdminPmTask::whereIn('id', $taskIds)
            ->update([
                'deleted_by' => auth()->id(),
            ]);

        return AdminPmTask::whereIn('id', $taskIds)->delete();
    }

    /**
     * 다중 작업 일괄 복원
     */
    public function bulkRestore(array $taskIds): int
    {
        return AdminPmTask::onlyTrashed()
            ->whereIn('id', $taskIds)
            ->update([
                'deleted_by' => null,
                'deleted_at' => null,
            ]);
    }

    /**
     * 작업 통계 (프로젝트별)
     */
    public function getTaskStatsByProject(int $projectId): array
    {
        return [
            'total' => AdminPmTask::where('project_id', $projectId)->count(),
            'todo' => AdminPmTask::where('project_id', $projectId)
                ->status(AdminPmTask::STATUS_TODO)->count(),
            'in_progress' => AdminPmTask::where('project_id', $projectId)
                ->status(AdminPmTask::STATUS_IN_PROGRESS)->count(),
            'done' => AdminPmTask::where('project_id', $projectId)
                ->status(AdminPmTask::STATUS_DONE)->count(),
            'overdue' => AdminPmTask::where('project_id', $projectId)->overdue()->count(),
            'due_soon' => AdminPmTask::where('project_id', $projectId)->dueSoon()->count(),
        ];
    }

    /**
     * 마감 임박/지연 작업 목록
     */
    public function getUrgentTasks(?int $projectId = null): array
    {
        $overdueQuery = AdminPmTask::overdue()->with('project', 'assignee');
        $dueSoonQuery = AdminPmTask::dueSoon()->with('project', 'assignee');

        if ($projectId) {
            $overdueQuery->where('project_id', $projectId);
            $dueSoonQuery->where('project_id', $projectId);
        }

        return [
            'overdue' => $overdueQuery->orderBy('due_date')->get(),
            'due_soon' => $dueSoonQuery->orderBy('due_date')->get(),
        ];
    }
}
