<?php

namespace App\Services\ProjectManagement;

use App\Models\Admin\AdminPmDailyLog;
use App\Models\Admin\AdminPmDailyLogEntry;
use App\Models\User;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

class DailyLogService
{
    /**
     * 일일 로그 목록 조회 (페이지네이션)
     */
    public function getDailyLogs(int $tenantId, array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = AdminPmDailyLog::query()
            ->tenant($tenantId)
            ->with(['project:id,name', 'creator:id,name', 'entries'])
            ->withCount('entries')
            ->withTrashed();

        // 날짜 범위 필터
        if (! empty($filters['start_date']) || ! empty($filters['end_date'])) {
            $query->dateRange($filters['start_date'] ?? null, $filters['end_date'] ?? null);
        }

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

        // 검색 필터 (요약 내용)
        if (! empty($filters['search'])) {
            $search = $filters['search'];
            $query->where(function ($q) use ($search) {
                $q->where('summary', 'like', "%{$search}%")
                    ->orWhereHas('entries', function ($eq) use ($search) {
                        $eq->where('content', 'like', "%{$search}%")
                            ->orWhere('assignee_name', 'like', "%{$search}%");
                    });
            });
        }

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

        // 정렬 (기본: 날짜 내림차순)
        $sortBy = $filters['sort_by'] ?? 'log_date';
        $sortDirection = $filters['sort_direction'] ?? 'desc';
        $query->orderBy($sortBy, $sortDirection);

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

    /**
     * 특정 일일 로그 조회
     */
    public function getDailyLogById(int $id, bool $withTrashed = false): ?AdminPmDailyLog
    {
        $query = AdminPmDailyLog::query()
            ->with(['project:id,name', 'creator:id,name', 'updater:id,name', 'entries']);

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

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

    /**
     * 특정 날짜의 로그 조회 (또는 생성)
     */
    public function getOrCreateByDate(int $tenantId, string $date, ?int $projectId = null): AdminPmDailyLog
    {
        $log = AdminPmDailyLog::query()
            ->tenant($tenantId)
            ->where('log_date', $date)
            ->where('project_id', $projectId)
            ->first();

        if (! $log) {
            $log = AdminPmDailyLog::create([
                'tenant_id' => $tenantId,
                'project_id' => $projectId,
                'log_date' => $date,
                'created_by' => auth()->id(),
            ]);
        }

        return $log->load('entries');
    }

    /**
     * 일일 로그 생성
     */
    public function createDailyLog(int $tenantId, array $data): AdminPmDailyLog
    {
        return DB::transaction(function () use ($tenantId, $data) {
            $log = AdminPmDailyLog::create([
                'tenant_id' => $tenantId,
                'project_id' => $data['project_id'] ?? null,
                'log_date' => $data['log_date'],
                'summary' => $data['summary'] ?? null,
                'created_by' => auth()->id(),
            ]);

            // 항목이 있으면 함께 생성
            if (! empty($data['entries'])) {
                $this->syncEntries($log, $data['entries']);
            }

            return $log->load('entries');
        });
    }

    /**
     * 일일 로그 수정
     */
    public function updateDailyLog(int $id, array $data): AdminPmDailyLog
    {
        return DB::transaction(function () use ($id, $data) {
            $log = AdminPmDailyLog::findOrFail($id);

            $log->update([
                'log_date' => $data['log_date'] ?? $log->log_date,
                'project_id' => $data['project_id'] ?? $log->project_id,
                'summary' => $data['summary'] ?? $log->summary,
                'updated_by' => auth()->id(),
            ]);

            // 항목 동기화
            if (isset($data['entries'])) {
                $this->syncEntries($log, $data['entries']);
            }

            return $log->fresh('entries');
        });
    }

    /**
     * 항목 동기화 (bulk upsert/delete)
     */
    protected function syncEntries(AdminPmDailyLog $log, array $entries): void
    {
        $existingIds = $log->entries()->pluck('id')->toArray();
        $incomingIds = [];

        foreach ($entries as $index => $entryData) {
            if (! empty($entryData['id'])) {
                // 기존 항목 업데이트
                $entry = AdminPmDailyLogEntry::find($entryData['id']);
                if ($entry && $entry->daily_log_id === $log->id) {
                    $entry->update([
                        'assignee_type' => $entryData['assignee_type'] ?? $entry->assignee_type,
                        'assignee_id' => $entryData['assignee_id'] ?? null,
                        'assignee_name' => $entryData['assignee_name'],
                        'content' => $entryData['content'],
                        'status' => $entryData['status'] ?? $entry->status,
                        'sort_order' => $index,
                    ]);
                    $incomingIds[] = $entry->id;
                }
            } else {
                // 새 항목 생성
                $entry = $log->entries()->create([
                    'assignee_type' => $entryData['assignee_type'] ?? 'user',
                    'assignee_id' => $entryData['assignee_id'] ?? null,
                    'assignee_name' => $entryData['assignee_name'],
                    'content' => $entryData['content'],
                    'status' => $entryData['status'] ?? 'todo',
                    'sort_order' => $index,
                ]);
                $incomingIds[] = $entry->id;
            }
        }

        // 제거된 항목 삭제
        $toDelete = array_diff($existingIds, $incomingIds);
        if (! empty($toDelete)) {
            AdminPmDailyLogEntry::whereIn('id', $toDelete)->delete();
        }
    }

    /**
     * 일일 로그 삭제 (Soft Delete)
     */
    public function deleteDailyLog(int $id): bool
    {
        $log = AdminPmDailyLog::findOrFail($id);

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

        return $log->delete();
    }

    /**
     * 일일 로그 복원
     */
    public function restoreDailyLog(int $id): bool
    {
        $log = AdminPmDailyLog::onlyTrashed()->findOrFail($id);

        $log->deleted_by = null;

        return $log->restore();
    }

    /**
     * 일일 로그 영구 삭제
     */
    public function forceDeleteDailyLog(int $id): bool
    {
        $log = AdminPmDailyLog::withTrashed()->findOrFail($id);

        return $log->forceDelete();
    }

    /**
     * 항목 수정
     */
    public function updateEntry(int $entryId, array $data): AdminPmDailyLogEntry
    {
        $entry = AdminPmDailyLogEntry::findOrFail($entryId);
        $entry->update($data);

        return $entry->fresh();
    }

    /**
     * 항목 상태 변경
     */
    public function updateEntryStatus(int $entryId, string $status): AdminPmDailyLogEntry
    {
        $entry = AdminPmDailyLogEntry::findOrFail($entryId);
        $entry->update(['status' => $status]);

        return $entry;
    }

    /**
     * 항목 추가
     */
    public function addEntry(int $logId, array $data): AdminPmDailyLogEntry
    {
        $log = AdminPmDailyLog::findOrFail($logId);

        // 마지막 정렬 순서 가져오기
        $maxOrder = $log->entries()->max('sort_order') ?? -1;

        return $log->entries()->create([
            'assignee_type' => $data['assignee_type'] ?? 'user',
            'assignee_id' => $data['assignee_id'] ?? null,
            'assignee_name' => $data['assignee_name'],
            'content' => $data['content'],
            'status' => $data['status'] ?? 'todo',
            'sort_order' => $maxOrder + 1,
        ]);
    }

    /**
     * 항목 삭제
     */
    public function deleteEntry(int $entryId): bool
    {
        return AdminPmDailyLogEntry::findOrFail($entryId)->delete();
    }

    /**
     * 항목 순서 변경
     */
    public function reorderEntries(int $logId, array $entryIds): void
    {
        foreach ($entryIds as $index => $entryId) {
            AdminPmDailyLogEntry::where('id', $entryId)
                ->where('daily_log_id', $logId)
                ->update(['sort_order' => $index]);
        }
    }

    /**
     * 통계 조회
     */
    public function getStats(int $tenantId, ?int $projectId = null): array
    {
        $query = AdminPmDailyLog::query()->tenant($tenantId);

        if ($projectId) {
            $query->project($projectId);
        }

        $totalLogs = $query->count();

        // 최근 7일 로그 수
        $recentLogs = (clone $query)
            ->where('log_date', '>=', now()->subDays(7)->format('Y-m-d'))
            ->count();

        // 전체 항목 통계
        $entryStats = AdminPmDailyLogEntry::query()
            ->whereHas('dailyLog', function ($q) use ($tenantId, $projectId) {
                $q->tenant($tenantId);
                if ($projectId) {
                    $q->project($projectId);
                }
            })
            ->selectRaw("
                COUNT(*) as total,
                SUM(CASE WHEN status = 'todo' THEN 1 ELSE 0 END) as todo,
                SUM(CASE WHEN status = 'in_progress' THEN 1 ELSE 0 END) as in_progress,
                SUM(CASE WHEN status = 'done' THEN 1 ELSE 0 END) as done
            ")
            ->first();

        return [
            'total_logs' => $totalLogs,
            'recent_logs' => $recentLogs,
            'entries' => [
                'total' => (int) ($entryStats->total ?? 0),
                'todo' => (int) ($entryStats->todo ?? 0),
                'in_progress' => (int) ($entryStats->in_progress ?? 0),
                'done' => (int) ($entryStats->done ?? 0),
            ],
        ];
    }

    /**
     * 주간 타임라인 데이터 조회 (최근 7일)
     */
    public function getWeeklyTimeline(int $tenantId, ?int $projectId = null): array
    {
        $days = [];
        $today = now();

        // 최근 7일 날짜 목록 생성
        for ($i = 6; $i >= 0; $i--) {
            $date = $today->copy()->subDays($i);
            $days[$date->format('Y-m-d')] = [
                'date' => $date->format('Y-m-d'),
                'day_name' => $date->locale('ko')->isoFormat('ddd'),
                'day_number' => $date->format('d'),
                'is_today' => $i === 0,
                'is_weekend' => $date->isWeekend(),
                'log' => null,
            ];
        }

        // 해당 기간의 로그 조회
        $startDate = $today->copy()->subDays(6)->format('Y-m-d');
        $endDate = $today->format('Y-m-d');

        $query = AdminPmDailyLog::query()
            ->tenant($tenantId)
            ->whereBetween('log_date', [$startDate, $endDate])
            ->with(['entries' => function ($q) {
                $q->select('id', 'daily_log_id', 'status');
            }]);

        if ($projectId) {
            $query->project($projectId);
        }

        $logs = $query->get();

        // 로그 데이터 매핑
        foreach ($logs as $log) {
            $dateKey = $log->log_date->format('Y-m-d');
            if (isset($days[$dateKey])) {
                $entryStats = [
                    'total' => $log->entries->count(),
                    'done' => $log->entries->where('status', 'done')->count(),
                    'in_progress' => $log->entries->where('status', 'in_progress')->count(),
                    'todo' => $log->entries->where('status', 'todo')->count(),
                ];

                $days[$dateKey]['log'] = [
                    'id' => $log->id,
                    'summary' => $log->summary,
                    'entry_stats' => $entryStats,
                    'completion_rate' => $entryStats['total'] > 0
                        ? round(($entryStats['done'] / $entryStats['total']) * 100)
                        : 0,
                ];
            }
        }

        return array_values($days);
    }

    /**
     * 담당자 목록 조회 (자동완성용)
     * - 일반 사용자는 슈퍼관리자 목록을 볼 수 없음
     */
    public function getAssigneeList(int $tenantId): array
    {
        // 사용자 목록
        $query = User::query()
            ->whereHas('tenants', function ($q) use ($tenantId) {
                $q->where('tenant_id', $tenantId);
            })
            ->where('is_active', true);

        // 슈퍼관리자가 아니면 슈퍼관리자 목록 제외
        if (! auth()->user()?->is_super_admin) {
            $query->where('is_super_admin', false);
        }

        $users = $query
            ->orderBy('name')
            ->get(['id', 'name'])
            ->map(fn ($u) => [
                'type' => 'user',
                'id' => $u->id,
                'name' => $u->name,
            ])
            ->toArray();

        // 팀 목록 (부서 활용)
        $teams = DB::table('departments')
            ->where('tenant_id', $tenantId)
            ->where('is_active', true)
            ->orderBy('name')
            ->get(['id', 'name'])
            ->map(fn ($d) => [
                'type' => 'team',
                'id' => $d->id,
                'name' => $d->name,
            ])
            ->toArray();

        return [
            'users' => $users,
            'teams' => $teams,
        ];
    }

    /**
     * 미완료 항목(예정, 진행중) 조회 - 담당자별 그룹핑, 날짜 오래된 순 정렬
     */
    public function getPendingEntries(int $tenantId, ?int $projectId = null, int $limit = 100): array
    {
        $query = AdminPmDailyLogEntry::query()
            ->select('admin_pm_daily_log_entries.*')
            ->with(['dailyLog:id,log_date,project_id', 'dailyLog.project:id,name'])
            ->join('admin_pm_daily_logs', 'admin_pm_daily_log_entries.daily_log_id', '=', 'admin_pm_daily_logs.id')
            ->where('admin_pm_daily_logs.tenant_id', $tenantId)
            ->when($projectId, fn ($q) => $q->where('admin_pm_daily_logs.project_id', $projectId))
            ->whereIn('admin_pm_daily_log_entries.status', ['todo', 'in_progress'])
            ->orderBy('admin_pm_daily_logs.log_date', 'asc')  // 날짜 오래된 순
            ->orderBy('admin_pm_daily_log_entries.id', 'asc')
            ->limit($limit);

        $entries = $query->get();

        // 담당자별로 그룹핑
        $grouped = $entries->groupBy('assignee_name')->map(function ($items, $assigneeName) {
            $todoItems = $items->where('status', 'todo');
            $inProgressItems = $items->where('status', 'in_progress');

            // 항목들을 날짜 오래된 순으로 정렬
            $sortedEntries = $items->sortBy(fn ($e) => $e->dailyLog?->log_date)->values();

            return [
                'assignee_name' => $assigneeName,
                'total_count' => $items->count(),
                'todo_count' => $todoItems->count(),
                'in_progress_count' => $inProgressItems->count(),
                'oldest_date' => $sortedEntries->first()?->dailyLog?->log_date,  // 카드 정렬용
                'entries' => $sortedEntries->map(function ($entry) {
                    return [
                        'id' => $entry->id,
                        'daily_log_id' => $entry->daily_log_id,
                        'log_date' => $entry->dailyLog?->log_date,
                        'project_name' => $entry->dailyLog?->project?->name,
                        'content' => $entry->content,
                        'status' => $entry->status,
                    ];
                })->values()->toArray(),
            ];
        });

        // 담당자 카드도 가장 오래된 항목 날짜 기준으로 정렬
        $sorted = $grouped->sortBy('oldest_date')->values()->toArray();

        return $sorted;
    }
}
