<?php

namespace App\Components\Report\Wip;

use App\Models\User\User;
use App\Models\WipEntry;
use Carbon\Carbon;
use Livewire\Component;

class Tracking extends Component
{
    public string $selectedDate;
    public int $selectedYear;

    public ?int $selectedUserId = null;

    public $selectedEntries = [];

    public string $dailySearch = '';
    public ?int $dailyUserId = null;

    public string $activeTab = 'daily';

    public function setActiveTab(string $tab): void
    {
        $this->activeTab = $tab;
    }

    public function mount(): void
    {
        $this->selectedDate = now()->toDateString();
        $this->selectedYear = now()->year;
    
        $this->dispatchChartsUpdated();
    
    }

    public function getDailyDataProperty(): array
    {
        return $this->dailyChartData();
    }

    public function getWeeklyDataProperty(): array
    {
        return $this->weeklyChartData();
    }

    public function getMonthlyDataProperty(): array
    {
        return $this->monthlyChartData();
    }

    public function updatedSelectedDate(): void
    {
        $this->selectedYear = Carbon::parse($this->selectedDate)->year;
    
        $this->dispatchChartsUpdated();
    }

    public function updatedSelectedYear(): void
    {
        $this->dispatchChartsUpdated();
    }

    private function dispatchChartsUpdated(): void
    {
        $this->dispatch(
            'wip-charts-updated',
            dailyData: $this->dailyData,
            weeklyData: $this->weeklyData,
            monthlyData: $this->monthlyData
        );
    }

    private function dailyChartData(): array
    {
        $entries = WipEntry::query()
            ->with('user')
            ->whereDate('started_at', $this->selectedDate)
            ->orderBy('started_at')
            ->get()
            ->groupBy('user_id');

        $labels = collect(range(8, 20))
            ->map(fn ($hour) => str_pad($hour, 2, '0', STR_PAD_LEFT) . ':00')
            ->values();

        $datasets = $entries->map(function ($items) use ($labels) {
            return [
                'label' => $items->first()->user?->name_first ?? 'Unknown',
                'userId' => $items->first()->user_id,
                'data' => $labels->map(function ($label) use ($items) {
                    $hour = (int) substr($label, 0, 2);

                    return (int) $items
                        ->filter(fn ($entry) => (int) $entry->started_at->format('H') <= $hour)
                        ->sum('units');
                })->values(),
            ];
        })->values();

        return [
            'type' => 'line',
            'title' => 'Daily WIP Tracking',
            'labels' => $labels,
            'datasets' => $datasets,
        ];
    }

    private function weeklyChartData(): array
    {
        $date = Carbon::parse($this->selectedDate);

        $start = $date->copy()->startOfWeek();
        $end = $date->copy()->endOfWeek();

        $labels = collect(range(0, 6))
            ->map(fn ($day) => $start->copy()->addDays($day)->format('D d M'))
            ->values();

        $rows = WipEntry::query()
            ->with('user')
            ->selectRaw('user_id, DATE(started_at) as entry_date, SUM(units) as units')
            ->whereBetween('started_at', [$start, $end])
            ->groupBy('user_id', 'entry_date')
            ->get()
            ->groupBy('user_id');

        $datasets = $rows->map(function ($items) use ($labels, $start) {
            return [
                'label' => $items->first()->user?->name_first ?? 'Unknown',
                'userId' => $items->first()->user_id,
                'data' => $labels->map(function ($label, $index) use ($items, $start) {
                    $date = $start->copy()->addDays($index)->toDateString();

                    return (int) ($items->firstWhere('entry_date', $date)?->units ?? 0);
                })->values(),
            ];
        })->values();

        return [
            'type' => 'bar',
            'title' => 'Weekly Units Recorded',
            'labels' => $labels,
            'datasets' => $datasets,
        ];
    }

    private function monthlyChartData(): array
    {
        $labels = collect(range(1, 12))
            ->map(fn ($month) => Carbon::create($this->selectedYear, $month)->format('M'))
            ->values();

        $rows = WipEntry::query()
            ->with('user')
            ->selectRaw('user_id, MONTH(started_at) as month, SUM(units) as units')
            ->whereYear('started_at', $this->selectedYear)
            ->groupBy('user_id', 'month')
            ->get()
            ->groupBy('user_id');

        $datasets = $rows->map(function ($items) use ($labels) {
            return [
                'label' => $items->first()->user?->name_first ?? 'Unknown',
                'userId' => $items->first()->user_id,
                'data' => $labels->map(function ($label, $index) use ($items) {
                    return (int) ($items->firstWhere('month', $index + 1)?->units ?? 0);
                })->values(),
            ];
        })->values();

        return [
            'type' => 'bar',
            'title' => 'Monthly Units Completed',
            'labels' => $labels,
            'datasets' => $datasets,
        ];
    }

    public function showEntries(string $period, int $userId, string $label): void
    {
        $this->selectedUserId = $userId;

        $query = WipEntry::query()
            ->with(['user', 'client', 'claim'])
            ->where('user_id', $userId);

        if ($period === 'daily') {
            $query->whereDate('started_at', $this->selectedDate);
        }

        if ($period === 'weekly') {
            $date = Carbon::parse($this->selectedDate);

            $query->whereBetween('started_at', [
                $date->copy()->startOfWeek(),
                $date->copy()->endOfWeek(),
            ]);
        }

        if ($period === 'monthly') {
            $month = Carbon::parse('1 ' . $label . ' ' . $this->selectedYear)->month;

            $query
                ->whereYear('started_at', $this->selectedYear)
                ->whereMonth('started_at', $month);
        }

        $this->selectedEntries = $query
            ->latest('started_at')
            ->get();
    }

    public function getMonthlyTableDataProperty(): array
    {
        $rows = WipEntry::query()
            ->with('user')
            ->selectRaw('user_id, MONTH(started_at) as month, SUM(units) as units')
            ->whereYear('started_at', $this->selectedYear)
            ->groupBy('user_id', 'month')
            ->get()
            ->groupBy('user_id');

        return $rows->map(function ($items) {
            return [
                'name' => $items->first()->user?->name_first ?? 'Unknown',
                'months' => collect(range(1, 12))
                    ->mapWithKeys(fn ($month) => [
                        $month => (int) ($items->firstWhere('month', $month)?->units ?? 0)
                    ])
                    ->toArray(),
            ];
        })->values()->toArray();
    }

    public function getDailyEntriesProperty()
    {
        return WipEntry::query()
            ->leftJoin('users', 'wip_entries.user_id', '=', 'users.id')
            ->leftJoin('clients', 'wip_entries.client_id', '=', 'clients.id')
            ->select([
                'wip_entries.*',
                'users.name_first as user_name_first',
                'users.name_last as user_name_last',
                'clients.id as joined_client_id',
                'clients.slug as client_slug',
                'clients.name_first as client_name_first',
                'clients.name_last as client_name_last',
            ])
            ->whereDate('wip_entries.started_at', $this->selectedDate)
            ->when($this->dailyUserId, fn ($query) =>
                $query->where('wip_entries.user_id', $this->dailyUserId)
            )
            ->when($this->dailySearch, function ($query) {
                $query->where(function ($q) {
                    $q->where('wip_entries.activity_type', 'like', '%' . $this->dailySearch . '%')
                        ->orWhere('wip_entries.description', 'like', '%' . $this->dailySearch . '%')
                        ->orWhere('users.name_first', 'like', '%' . $this->dailySearch . '%')
                        ->orWhere('users.name_last', 'like', '%' . $this->dailySearch . '%')
                        ->orWhere('clients.name_first', 'like', '%' . $this->dailySearch . '%')
                        ->orWhere('clients.name_last', 'like', '%' . $this->dailySearch . '%')
                        ->orWhereRaw(
                            "CONCAT('1', LPAD(clients.id, 5, '0')) LIKE ?",
                            ['%' . $this->dailySearch . '%']
                        );
                });
            })
            ->latest('wip_entries.started_at')
            ->get();
    }   

    public function render()
    {
        return view('components.report.wip.tracking', [
            'dailyData' => $this->dailyData,
            'weeklyData' => $this->weeklyData,
            'monthlyData' => $this->monthlyData,
            'monthlyTableData' => $this->monthlyTableData,
            'dailyEntries' => $this->dailyEntries,
        ]);
    }
}