<?php

namespace App\Http\Controllers;

use App\Models\Diary;
use App\Models\DiaryCategory;
use App\Models\DiaryTag;
use App\Models\User;
use App\Services\DiaryService;
use App\Models\DiaryQuickEntry;
use Carbon\Carbon;
use Illuminate\Http\Request;
 
class DiaryController extends Controller
{
    protected $diaryService;

    public function __construct(DiaryService $diaryService)
    {
        $this->diaryService = $diaryService;
    }

    public function index()
    {
        return $this->dashboard(request());
    }

    public function create()
    {
        $categories = DiaryCategory::active()->get();
        $tags = DiaryTag::active()->get();
        $assignees = User::orderBy('name')->get();

        return view('modules.processing.diary.contextual-entry', compact('categories', 'tags', 'assignees'));
    }

    public function store(Request $request)
    {
        $rules = $this->validationRules($request);
        $validated = $request->validate($rules);

        $durationData = $this->buildDuration($request);
        unset($validated['duration_hours'], $validated['duration_minutes']);
        $validated = array_merge($validated, $durationData);

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

        $tagIds = $request->input('tags', []);

        $diary = Diary::create($validated);
        if ($tagIds) {
            $this->syncTags($diary, $tagIds);
        }

        return redirect()
            ->route('modules.processing.diary.list')
            ->with('success', 'Diary entry created successfully.');
    }

    public function show($id)
    {
        $diaryEntry = Diary::withRelations()->findOrFail($id);
        return view('modules.processing.diary.diary-show', compact('diaryEntry'));
    }

    public function edit($id)
    {
        $diaryEntry = Diary::withRelations()->findOrFail($id);

        $durationParts = $this->parseDuration($diaryEntry->duration, $diaryEntry->duration_minutes);
        $durationHours = $durationParts['hours'];
        $durationMinutes = $durationParts['minutes'];

        $categories = DiaryCategory::active()->get();
        $tags = DiaryTag::active()->get();
        $assignees = User::orderBy('name')->get();

        return view('modules.processing.diary.edit-diary', compact(
            'diaryEntry',
            'durationHours',
            'durationMinutes',
            'categories',
            'tags',
            'assignees'
        ));
    }

    public function update(Request $request, $id)
    {
        $diaryEntry = Diary::findOrFail($id);

        $rules = $this->validationRules($request, false);
        $validated = $request->validate($rules);

        $durationData = $this->buildDuration($request);
        unset($validated['duration_hours'], $validated['duration_minutes']);
        $validated = array_merge($validated, $durationData);

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

        $diaryEntry->update($validated);

        $tagIds = $request->input('tags', []);
        $this->syncTags($diaryEntry, $tagIds);

        return redirect()
            ->route('modules.processing.diary.list')
            ->with('success', 'Diary entry updated successfully.');
    }

    public function destroy($id)
    {
        $diaryEntry = Diary::findOrFail($id);
        $diaryEntry->delete();

        return redirect()
            ->route('modules.processing.diary.list')
            ->with('success', 'Diary entry deleted successfully.');
    }

    public function updateStatus(Request $request, Diary $diary)
    {
        $request->validate([
            'status' => 'required|in:pending,in-progress,completed,deferred',
        ]);

        $isCompleted = $request->status === 'completed';
        $diary->update([
            'status' => $request->status,
            'is_completed' => $isCompleted,
            'completed_at' => $isCompleted ? now() : null,
            'completed_by' => $isCompleted ? auth()->id() : null,
        ]);

        return back()->with('success', 'Status updated successfully.');
    }

    public function bulkDelete(Request $request)
    {
        $ids = $request->input('ids', []);
        if (!empty($ids)) {
            Diary::whereIn('id', array_map('intval', $ids))->delete();
        }

        return redirect()
            ->route('modules.processing.diary.list')
            ->with('success', count($ids) . ' entries deleted successfully.');
    }

    public function today(Request $request)
    {
        $filters = $request->only(['status', 'priority', 'task_type', 'start_date', 'end_date']);
        $filters['today'] = true;
        $diaryEntries = $this->diaryService->getCombinedEntries($filters);
        
        $perPage = 15;
        $page = $request->get('page', 1);
        $paginated = new \Illuminate\Pagination\LengthAwarePaginator(
            $diaryEntries->forPage($page, $perPage),
            $diaryEntries->count(),
            $perPage,
            $page,
            ['path' => $request->url(), 'pageName' => 'page']
        );

        $diaryEntriesPaginated = $paginated;
        return view('modules.processing.diary.diary-list', compact('diaryEntries', 'diaryEntriesPaginated'));
    }

    public function upcoming(Request $request)
    {
        $filters = $request->only(['status', 'priority', 'task_type', 'start_date', 'end_date']);
        $filters['upcoming'] = true;
        $diaryEntries = $this->diaryService->getCombinedEntries($filters);

        return view('modules.processing.diary.diary-list', compact('diaryEntries'));
    }

    public function overdue(Request $request)
    {
        $filters = $request->only(['status', 'priority', 'task_type', 'start_date', 'end_date']);
        $filters['overdue'] = true;
        $diaryEntries = $this->diaryService->getCombinedEntries($filters);

        return view('modules.processing.diary.diary-list', compact('diaryEntries'));
    }

    public function byStatus(Request $request, $status)
    {
        $filters = $request->only(['priority', 'task_type', 'start_date', 'end_date']);
        $filters['status'] = $status;
        $diaryEntries = $this->diaryService->getCombinedEntries($filters);

        return view('modules.processing.diary.diary-list', compact('diaryEntries'));
    }

    public function byPriority(Request $request, $priority)
    {
        $filters = $request->only(['status', 'task_type', 'start_date', 'end_date']);
        $filters['priority'] = $priority;
        $diaryEntries = $this->diaryService->getCombinedEntries($filters);

        return view('modules.processing.diary.diary-list', compact('diaryEntries'));
    }

    public function byTaskType(Request $request, $taskType)
    {
        $filters = $request->only(['status', 'priority', 'start_date', 'end_date']);
        $filters['task_type'] = $taskType;
        $diaryEntries = $this->diaryService->getCombinedEntries($filters);

        return view('modules.processing.diary.diary-list', compact('diaryEntries'));
    }

    public function dashboard(Request $request)
    {
        $stats = $this->diaryService->getDashboardStats();
        $today = Carbon::today();

        $selectedDate = $today;
        if ($request->filled('date')) {
            try {
                $selectedDate = Carbon::parse($request->query('date'))->startOfDay();
            } catch (\Throwable $e) {
                $selectedDate = $today;
            }
        }

        $todayCount = (int) ($stats['today'] ?? 0);
        $totalCount = (int) ($stats['total'] ?? 0);

        $completedCount = \DB::table('diary_contextual_entries')->where('status', 'completed')->count()
            + \DB::table('diary_quick_entries')->where('is_completed', true)->count();
        $pendingCount = \DB::table('diary_contextual_entries')->where('status', 'pending')->count()
            + \DB::table('diary_quick_entries')->where('is_completed', false)->count();
        $inProgressCount = \DB::table('diary_contextual_entries')->where('status', 'in-progress')->count();

        $upcomingCount = \DB::table('diary_contextual_entries')->where('date_time', '>', $today)->where('status', '!=', 'completed')->count()
            + DiaryQuickEntry::where('is_completed', false)->whereDate('entry_date', '>', $today->toDateString())->count();
        $overdueCount = \DB::table('diary_contextual_entries')->where('date_time', '<', now())->whereNotIn('status', ['completed', 'deferred'])->count()
            + DiaryQuickEntry::where('is_completed', false)->whereDate('entry_date', '<', $today->toDateString())->count();

        $completionRate = $totalCount > 0
            ? round(((int) ($stats['completed'] ?? 0) / $totalCount) * 100)
            : 0;

        $weeklyTrend = collect(range(6, 0))->map(function ($daysAgo) {
            $date = Carbon::today()->subDays($daysAgo);
            return [
                'label' => $date->format('D'),
                'count' => \DB::table('diary_contextual_entries')->whereDate('date_time', $date)->count()
                    + DiaryQuickEntry::where('is_completed', false)->whereDate('entry_date', $date)->count(),
            ];
        });

        $recentEntries = $this->diaryService->getCombinedEntries()->take(10);
        $dailyEntries = $this->diaryService->getCombinedEntries([
            'start_date' => $selectedDate->toDateString(),
            'end_date' => $selectedDate->toDateString(),
        ])->sortBy('entry_date')->values();

        return view('modules.processing.diary.diary-dashboard', compact(
            'stats',
            'completionRate',
            'weeklyTrend',
            'recentEntries',
            'dailyEntries',
            'selectedDate',
            'todayCount',
            'upcomingCount',
            'overdueCount',
            'totalCount',
            'completedCount',
            'pendingCount',
            'inProgressCount',
        ));
    }

    public function entryShow(string $type, int $id)
    {
        if ($type === 'contextual') {
            return $this->show($id);
        }

        $entry = DiaryQuickEntry::findOrFail($id);

        return view('modules.processing.diary.quick-show', [
            'entry' => $entry,
            'type' => $type,
        ]);
    }

    public function entryEdit(string $type, int $id)
    {
        if ($type === 'contextual') {
            return $this->edit($id);
        }

        $entry = DiaryQuickEntry::findOrFail($id);
        $assignees = User::orderBy('name')->get();

        return view('modules.processing.diary.quick-edit', [
            'entry' => $entry,
            'assignees' => $assignees,
            'type' => $type,
        ]);
    }

    public function entryUpdate(Request $request, string $type, int $id)
    {
        if ($type === 'contextual') {
            return $this->update($request, $id);
        }

        $entry = DiaryQuickEntry::findOrFail($id);

        $validated = $request->validate([
            'entry_date' => 'required|date',
            'task_type' => 'nullable|string|max:50',
            'task_title' => 'required|string|max:255',
            'assigned_to' => 'nullable|exists:users,id',
            'notes' => 'nullable|string|max:1000',
        ]);

        $validated['updated_by'] = auth()->id();
        $entry->update($validated);

        return redirect()
            ->back()
            ->with('success', 'Quick diary entry updated successfully.');
    }

    public function entryDestroy(string $type, int $id)
    {
        if ($type === 'contextual') {
            return $this->destroy($id);
        }

        $entry = DiaryQuickEntry::findOrFail($id);
        $entry->delete();

        return redirect()
            ->back()
            ->with('success', 'Quick diary entry deleted successfully.');
    }

    public function entryToggleComplete(Request $request, string $type, int $id)
    {
        $request->validate([
            'is_completed' => 'nullable|boolean',
        ]);

        $userId = auth()->id();

        if ($type === 'contextual') {
            $entry = Diary::findOrFail($id);
            $newState = $request->has('is_completed')
                ? (bool) $request->boolean('is_completed')
                : !(bool) ($entry->is_completed ?? false);

            $updates = [
                'is_completed' => $newState,
                'completed_at' => $newState ? now() : null,
                'completed_by' => $newState ? $userId : null,
                'updated_by' => $userId,
            ];

            if ($newState) {
                $updates['status'] = 'completed';
            } elseif (($entry->status ?? '') === 'completed') {
                $updates['status'] = 'pending';
            }

            $entry->update($updates);
        } else {
            $entry = DiaryQuickEntry::findOrFail($id);
            $newState = $request->has('is_completed')
                ? (bool) $request->boolean('is_completed')
                : !(bool) ($entry->is_completed ?? false);

            $entry->update([
                'is_completed' => $newState,
                'completed_at' => $newState ? now() : null,
                'completed_by' => $newState ? $userId : null,
                'updated_by' => $userId,
            ]);
        }

        if ($request->expectsJson()) {
            return response()->json([
                'ok' => true,
                'is_completed' => $newState,
            ]);
        }

        return back()->with('success', $newState ? 'Marked as completed.' : 'Marked as pending.');
    }

    public function entryPrint(string $type, int $id)
    {
        if ($type === 'contextual') {
            $entry = Diary::withRelations()->findOrFail($id);
        } else {
            $entry = DiaryQuickEntry::findOrFail($id);
        }

        return view('modules.processing.diary.entry-print', [
            'entry' => $entry,
            'type' => $type,
        ]);
    }

    public function calendar()
    {
        $diaryEntries = Diary::query()
            ->when(auth()->check(), function ($q) {
                return $q->where('assigned_to', auth()->id());
            })
            ->get()
            ->map(function ($entry) {
                $entryId = $entry->getKey() ?? $entry->id ?? $entry->diary_id;

                return [
                    'id' => $entryId,
                    'title' => $entry->task_title
                        . ($entry->client_case ? ' — ' . $entry->client_case : ''),
                    'start' => optional($entry->date_time)->toIso8601String(),
                    'url' => $entryId ? route('modules.processing.diary.show', $entryId) : null,
                    'className' => $entry->priority,
                    'extendedProps' => [
                        'status' => $entry->status,
                        'priority' => $entry->priority,
                    ],
                ];
            });

        return view('modules.processing.diary.diary-calendar', compact('diaryEntries'));
    }

    public function createFromDate(Request $request)
    {
        $date = $request->query('date');
        return redirect()->route('modules.processing.diary.add', ['date' => $date]);
    }

    public function quickCreate()
    {
        $assignees = User::orderBy('name')->get();
        return view('modules.processing.diary.quick-entry', compact('assignees'));
    }

    public function quickStore(Request $request)
    {
        $validated = $request->validate([
            'entry_date' => 'required|date',
            'task_type' => 'nullable|string|max:50',
            'task_title' => 'required|string|max:255',
            'assigned_to' => 'nullable|exists:users,id',
            'notes' => 'nullable|string|max:1000',
        ]);

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

        DiaryQuickEntry::create($validated);

        return redirect()->route('modules.processing.diary.dashboard')
            ->with('success', 'Quick diary entry created successfully.');
    }




    private function validationRules(Request $request, bool $enforceFutureDate = true): array
    {
        $rules = [
            'date_time' => 'required|date',
            'task_title' => 'required|string|max:255',
            'client_case' => 'nullable|string|max:255',
            'task_type' => 'required|in:meeting,draft-review,call,follow-up,internal-task,assignment,other',
            'priority' => 'required|in:low,medium,high',
            'status' => 'required|in:pending,in-progress,completed,deferred',
            'location' => 'nullable|in:office,courtroom,online-meeting,phone-call,other',
            'duration' => 'nullable|string|max:50',
            'notes' => 'nullable|string|max:1000',
            'duration_hours' => 'nullable|integer|min:0|max:12',
            'duration_minutes' => 'nullable|integer|in:0,15,30,45',
            'category_id' => 'nullable|exists:diary_categories,id',
            'assigned_to' => 'nullable|exists:users,id|required_if:task_type,assignment',
            'tags' => 'nullable|array',
            'tags.*' => 'integer|exists:diary_tags,id',
        ];

        if ($request->isMethod('POST') && $enforceFutureDate) {
            $rules['date_time'] = 'required|date|after_or_equal:now';
        }

        return $rules;
    }

    private function buildDuration(Request $request): array
    {
        $hours = $request->input('duration_hours');
        $minutes = $request->input('duration_minutes');

        if (($hours === null || $hours === '') && ($minutes === null || $minutes === '')) {
            return ['duration' => null, 'duration_minutes' => null];
        }

        $h = is_numeric($hours) ? (int) $hours : 0;
        $m = is_numeric($minutes) ? (int) $minutes : 0;

        if ($h === 0 && $m === 0) {
            return ['duration' => null, 'duration_minutes' => null];
        }

        $duration = trim($h . 'h ' . $m . 'm');
        $totalMinutes = ($h * 60) + $m;

        return [
            'duration' => $duration ?: null,
            'duration_minutes' => $totalMinutes > 0 ? $totalMinutes : null,
        ];
    }

    private function parseDuration(?string $duration, ?int $durationMinutes = null): array
    {
        $hours = '';
        $minutes = '';

        if ($durationMinutes !== null) {
            $hours = intdiv($durationMinutes, 60);
            $minutes = $durationMinutes % 60;
            return ['hours' => $hours, 'minutes' => $minutes];
        }

        if ($duration) {
            if (preg_match('/(\d+)\s*h/i', $duration, $hMatch)) {
                $hours = (int) $hMatch[1];
            }
            if (preg_match('/(\d+)\s*m/i', $duration, $mMatch)) {
                $minutes = (int) $mMatch[1];
            }
        }

        return ['hours' => $hours, 'minutes' => $minutes];
    }

    private function syncTags(Diary $diary, array $tagIds): void
    {
        $tagIds = array_values(array_unique(array_map('intval', $tagIds)));
        $currentTagIds = $diary->tags()->pluck('diary_tags.id')->map(fn ($id) => (int) $id)->all();

        $toAttach = array_diff($tagIds, $currentTagIds);
        $toDetach = array_diff($currentTagIds, $tagIds);

        if (!empty($toAttach)) {
            DiaryTag::whereIn('id', $toAttach)->increment('usage_count');
        }

        if (!empty($toDetach)) {
            DiaryTag::whereIn('id', $toDetach)->where('usage_count', '>', 0)->decrement('usage_count');
        }

        $diary->tags()->sync($tagIds);
    }
}
