<?php

namespace App\Http\Controllers;

use App\Models\Boards\File;
use App\Models\System\Holiday;
use App\Models\System\Schedule;
use App\Services\GoogleCloudStorageService;
use Carbon\Carbon;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class DashboardCalendarController extends Controller
{
    /**
     * 달력 partial 반환 (HTMX용)
     */
    public function calendar(Request $request): View
    {
        $year = (int) $request->input('year', now()->year);
        $month = (int) $request->input('month', now()->month);
        $tenantId = session('selected_tenant_id', 1);

        $firstDay = Carbon::create($year, $month, 1);
        $lastDay = $firstDay->copy()->endOfMonth();
        $startOfWeek = $firstDay->copy()->startOfWeek(Carbon::SUNDAY);
        $endOfWeek = $lastDay->copy()->endOfWeek(Carbon::SATURDAY);

        $calendarData = Schedule::forTenant($tenantId)
            ->active()
            ->betweenDates($startOfWeek->toDateString(), $endOfWeek->toDateString())
            ->withCount('files')
            ->orderBy('start_date')
            ->orderBy('start_time')
            ->get()
            ->groupBy(fn ($s) => $s->start_date->format('Y-m-d'));

        $holidayMap = $this->getHolidayMap($tenantId, $year, $month);

        return view('dashboard.partials.calendar', compact(
            'year', 'month', 'calendarData', 'holidayMap'
        ));
    }

    /**
     * 일정 등록
     */
    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'description' => 'nullable|string|max:1000',
            'start_date' => 'required|date',
            'end_date' => 'nullable|date|after_or_equal:start_date',
            'start_time' => 'nullable|date_format:H:i',
            'end_time' => 'nullable|date_format:H:i',
            'is_all_day' => 'boolean',
            'type' => 'required|string|max:50',
            'color' => 'nullable|string|max:20',
        ]);

        $tenantId = session('selected_tenant_id', 1);

        $validated['tenant_id'] = $tenantId;
        $validated['created_by'] = auth()->id();
        $validated['is_all_day'] = $validated['is_all_day'] ?? true;

        if (empty($validated['end_date'])) {
            $validated['end_date'] = $validated['start_date'];
        }

        $schedule = Schedule::create($validated);

        return response()->json([
            'success' => true,
            'message' => '일정이 등록되었습니다.',
            'data' => $schedule,
        ]);
    }

    /**
     * 일정 상세 (JSON)
     */
    public function show(int $id): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);

        $schedule = Schedule::forTenant($tenantId)->findOrFail($id);

        // 첨부파일 목록
        $files = File::where('document_type', 'schedule')
            ->where('document_id', $id)
            ->whereNull('deleted_at')
            ->get(['id', 'display_name', 'original_name', 'file_size', 'mime_type', 'created_at']);

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

    /**
     * 일정 수정
     */
    public function update(Request $request, int $id): JsonResponse
    {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'description' => 'nullable|string|max:1000',
            'start_date' => 'required|date',
            'end_date' => 'nullable|date|after_or_equal:start_date',
            'start_time' => 'nullable|date_format:H:i',
            'end_time' => 'nullable|date_format:H:i',
            'is_all_day' => 'boolean',
            'type' => 'required|string|max:50',
            'color' => 'nullable|string|max:20',
        ]);

        $tenantId = session('selected_tenant_id', 1);
        $schedule = Schedule::forTenant($tenantId)->findOrFail($id);

        $validated['updated_by'] = auth()->id();
        $validated['is_all_day'] = $validated['is_all_day'] ?? true;

        if (empty($validated['end_date'])) {
            $validated['end_date'] = $validated['start_date'];
        }

        $schedule->update($validated);

        return response()->json([
            'success' => true,
            'message' => '일정이 수정되었습니다.',
            'data' => $schedule->fresh(),
        ]);
    }

    /**
     * 일정 삭제
     */
    public function destroy(int $id): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);
        $schedule = Schedule::forTenant($tenantId)->findOrFail($id);

        $schedule->update(['deleted_by' => auth()->id()]);
        $schedule->delete();

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

    /**
     * 파일 업로드 (다중)
     */
    public function uploadFiles(Request $request, int $scheduleId, GoogleCloudStorageService $gcs): JsonResponse
    {
        $request->validate([
            'files' => 'required|array|min:1',
            'files.*' => 'file|max:20480', // 20MB
        ]);

        $tenantId = session('selected_tenant_id', 1);
        $schedule = Schedule::forTenant($tenantId)->findOrFail($scheduleId);

        $uploaded = [];

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

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

            // GCS 업로드 (가능한 경우)
            $gcsUri = null;
            if ($gcs->isAvailable()) {
                $gcsObjectName = "schedules/{$tenantId}/{$schedule->id}/{$storedName}";
                $gcsUri = $gcs->upload($file->getRealPath(), $gcsObjectName);
            }

            // DB 레코드
            $fileRecord = File::create([
                'tenant_id' => $tenantId,
                'document_type' => 'schedule',
                'document_id' => $schedule->id,
                'file_path' => $storagePath,
                'display_name' => $originalName,
                'stored_name' => $storedName,
                'original_name' => $originalName,
                'file_name' => $originalName,
                'file_size' => $file->getSize(),
                'mime_type' => $file->getMimeType(),
                'file_type' => $this->determineFileType($file->getMimeType()),
                'is_temp' => false,
                'uploaded_by' => auth()->id(),
                'created_by' => auth()->id(),
            ]);

            $uploaded[] = [
                'id' => $fileRecord->id,
                'name' => $originalName,
                'size' => $fileRecord->getFormattedSize(),
                'gcs' => $gcsUri ? true : false,
            ];
        }

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

    /**
     * 파일 삭제
     */
    public function deleteFile(int $scheduleId, int $fileId, GoogleCloudStorageService $gcs): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);
        Schedule::forTenant($tenantId)->findOrFail($scheduleId);

        $file = File::where('document_type', 'schedule')
            ->where('document_id', $scheduleId)
            ->where('id', $fileId)
            ->firstOrFail();

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

        // 로컬 삭제
        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' => '파일이 삭제되었습니다.',
        ]);
    }

    /**
     * 파일 다운로드
     */
    public function downloadFile(int $scheduleId, int $fileId)
    {
        $tenantId = session('selected_tenant_id', 1);
        Schedule::forTenant($tenantId)->findOrFail($scheduleId);

        $file = File::where('document_type', 'schedule')
            ->where('document_id', $scheduleId)
            ->where('id', $fileId)
            ->firstOrFail();

        return $file->download();
    }

    /**
     * MIME 타입으로 파일 유형 결정
     */
    private function determineFileType(string $mimeType): string
    {
        if (str_starts_with($mimeType, 'image/')) {
            return 'image';
        }
        if (str_contains($mimeType, 'spreadsheet') || str_contains($mimeType, 'excel')) {
            return 'excel';
        }
        if (str_contains($mimeType, 'zip') || str_contains($mimeType, 'rar') || str_contains($mimeType, 'archive')) {
            return 'archive';
        }

        return 'document';
    }

    /**
     * 해당 월의 휴일 맵 생성 (날짜 => 휴일명)
     */
    private function getHolidayMap(int $tenantId, int $year, int $month): array
    {
        $startOfMonth = Carbon::create($year, $month, 1)->startOfWeek(Carbon::SUNDAY);
        $endOfMonth = Carbon::create($year, $month, 1)->endOfMonth()->endOfWeek(Carbon::SATURDAY);

        $holidays = Holiday::forTenant($tenantId)
            ->where('start_date', '<=', $endOfMonth->toDateString())
            ->where('end_date', '>=', $startOfMonth->toDateString())
            ->get();

        $map = [];
        foreach ($holidays as $holiday) {
            $start = $holiday->start_date->copy();
            $end = $holiday->end_date->copy();
            for ($d = $start; $d->lte($end); $d->addDay()) {
                $map[$d->format('Y-m-d')] = $holiday->name;
            }
        }

        return $map;
    }
}
