<?php

namespace App\Http\Controllers\Admin;

use App\Core\Repositories\CustomerRepository;
use App\Core\Repositories\InvoiceRepository;
use App\Core\Repositories\PaymentRepository;
use App\Http\Controllers\Controller;
use App\Models\Customer;
use App\Models\Invoice;
use App\Models\Note;
use App\Models\Payment;
use App\Models\Purchase;
use App\Models\Quotation;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;

class DashboardController extends Controller
{
    public function __construct(
        private InvoiceRepository $invoiceRepository,
        private CustomerRepository $customerRepository,
        private PaymentRepository $paymentRepository
    ) {}

    /**
     * Display the admin dashboard
     */
    public function index(): View
    {
        // Get statistics
        $totalInvoices = Invoice::count();
        $totalRevenue = Invoice::where('status', 'paid')->sum('total');
        $outstanding = Invoice::where('status', '!=', 'paid')->sum('balance');
        $newClients = Customer::whereMonth('created_at', now()->month)->count();

        $paidInvoicesCount = Invoice::where('status', 'paid')->count();
        $overdueInvoicesCount = Invoice::query()
            ->whereNotIn('status', ['paid', 'cancelled'])
            ->where('balance', '>', 0)
            ->whereNotNull('due_date')
            ->whereDate('due_date', '<', now()->toDateString())
            ->count();
        $pendingInvoicesCount = Invoice::query()
            ->whereNotIn('status', ['paid', 'cancelled'])
            ->where('balance', '>', 0)
            ->where(function ($q) {
                $q->whereNull('due_date')->orWhereDate('due_date', '>=', now()->toDateString());
            })
            ->count();

        $totalCustomers = Customer::count();
        $monthIncome = Invoice::query()
            ->where('status', 'paid')
            ->whereYear('issue_date', now()->year)
            ->whereMonth('issue_date', now()->month)
            ->sum('total');

        $overdueAmount = Invoice::query()
            ->whereNotIn('status', ['paid', 'cancelled'])
            ->where('balance', '>', 0)
            ->whereNotNull('due_date')
            ->whereDate('due_date', '<', now()->toDateString())
            ->sum('balance');
        $pendingCollectionAmount = max(0, (float) $outstanding - (float) $overdueAmount);

        $collectionTotal = (float) $totalRevenue + (float) $outstanding;
        $collectionCollectedPct = $collectionTotal > 0 ? round(((float) $totalRevenue / $collectionTotal) * 100) : 0;
        $collectionPendingPct = $collectionTotal > 0 ? round(((float) $pendingCollectionAmount / $collectionTotal) * 100) : 0;
        $collectionOverduePct = $collectionTotal > 0 ? max(0, 100 - $collectionCollectedPct - $collectionPendingPct) : 0;

        $recentPayments = Payment::with(['customer', 'invoice'])
            ->orderByDesc('payment_date')
            ->orderByDesc('id')
            ->limit(5)
            ->get();

        $recentQuotations = Quotation::with('customer')
            ->orderByDesc('created_at')
            ->limit(5)
            ->get();

        $recentPurchases = Purchase::with('supplier')
            ->orderByDesc('purchase_date')
            ->orderByDesc('id')
            ->limit(5)
            ->get();

        $upcomingDueInvoices = Invoice::with('customer')
            ->whereNotIn('status', ['paid', 'cancelled'])
            ->where('balance', '>', 0)
            ->whereNotNull('due_date')
            ->whereBetween('due_date', [now()->startOfDay(), now()->copy()->addDays(14)->endOfDay()])
            ->orderBy('due_date')
            ->limit(5)
            ->get();

        $hour = (int) now()->format('G');
        $greeting = match (true) {
            $hour < 12 => 'Good morning',
            $hour < 17 => 'Good afternoon',
            default => 'Good evening',
        };

        // Calculate growth percentages (mock for now, can be improved with actual data)
        $invoiceGrowth = 12; // +12%
        $revenueGrowth = 8; // +8%
        $outstandingGrowth = -2; // -2%
        $clientsGrowth = 5; // +5%

        // Get recent invoices
        $recentInvoices = $this->invoiceRepository->getPaginated(5, []);

        // Get top customers by revenue
        $topCustomers = Customer::with('invoices')
            ->has('invoices')
            ->get()
            ->map(function ($customer) {
                $customer->total_revenue = $customer->invoices->sum('total');
                $customer->invoice_count = $customer->invoices->count();

                return $customer;
            })
            ->sortByDesc('total_revenue')
            ->take(4)
            ->values();

        // Get monthly revenue data for chart (last 6 months)
        $monthlyRevenue = [];
        $monthlyExpenses = [];
        $months = [];

        for ($i = 5; $i >= 0; $i--) {
            $date = now()->subMonths($i);
            $months[] = $date->format('M');

            $monthlyRevenue[] = Invoice::whereYear('created_at', $date->year)
                ->whereMonth('created_at', $date->month)
                ->where('status', 'paid')
                ->sum('total');

            try {
                $monthlyExpenses[] = \App\Models\Expense::whereYear('expense_date', $date->year)
                    ->whereMonth('expense_date', $date->month)
                    ->where('status', 'approved')
                    ->sum('amount') ?? 0;
            } catch (\Exception $e) {
                $monthlyExpenses[] = 0;
            }
        }

        // Get quick notes (pinned and recent)
        $notes = Note::where('created_by', Auth::id())
            ->orderBy('is_pinned', 'desc')
            ->orderBy('created_at', 'desc')
            ->limit(20)
            ->get();

        return view('admin.dashboard', [
            'totalInvoices' => $totalInvoices,
            'totalRevenue' => $totalRevenue,
            'outstanding' => $outstanding,
            'newClients' => $newClients,
            'invoiceGrowth' => $invoiceGrowth,
            'revenueGrowth' => $revenueGrowth,
            'outstandingGrowth' => $outstandingGrowth,
            'clientsGrowth' => $clientsGrowth,
            'paidInvoicesCount' => $paidInvoicesCount,
            'pendingInvoicesCount' => $pendingInvoicesCount,
            'overdueInvoicesCount' => $overdueInvoicesCount,
            'totalCustomers' => $totalCustomers,
            'monthIncome' => $monthIncome,
            'overdueAmount' => $overdueAmount,
            'pendingCollectionAmount' => $pendingCollectionAmount,
            'collectionTotal' => $collectionTotal,
            'collectionCollectedPct' => $collectionCollectedPct,
            'collectionPendingPct' => $collectionPendingPct,
            'collectionOverduePct' => $collectionOverduePct,
            'recentInvoices' => $recentInvoices,
            'recentPayments' => $recentPayments,
            'recentQuotations' => $recentQuotations,
            'recentPurchases' => $recentPurchases,
            'upcomingDueInvoices' => $upcomingDueInvoices,
            'topCustomers' => $topCustomers,
            'monthlyRevenue' => $monthlyRevenue,
            'monthlyExpenses' => $monthlyExpenses,
            'months' => $months,
            'notes' => $notes,
            'greeting' => $greeting,
        ]);
    }

    /**
     * Get calendar data for a specific month
     */
    public function getCalendar(Request $request): JsonResponse
    {
        $year = $request->input('year', now()->year);
        $month = $request->input('month', now()->month);

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

        $calendarDays = [];
        $currentDay = $firstDay->copy();

        while ($currentDay <= $lastDay) {
            $calendarDays[] = [
                'day' => $currentDay->day,
                'month' => $currentDay->month,
                'year' => $currentDay->year,
                'isCurrentMonth' => $currentDay->month == $date->month,
                'isToday' => $currentDay->isSameDay(now()),
                'date' => $currentDay->format('Y-m-d'),
            ];
            $currentDay->addDay();
        }

        // Get events/notes for this month
        $events = Note::where('created_by', Auth::id())
            ->whereYear('due_date', $year)
            ->whereMonth('due_date', $month)
            ->get()
            ->map(function ($note) {
                return [
                    'id' => $note->id,
                    'title' => $note->title,
                    'date' => $note->due_date ? $note->due_date->format('Y-m-d') : null,
                    'type' => $note->type,
                ];
            });

        return response()->json([
            'success' => true,
            'month' => $date->format('F Y'),
            'year' => $year,
            'monthNumber' => $month,
            'days' => $calendarDays,
            'events' => $events,
        ]);
    }

    /**
     * Get notes
     */
    public function getNotes(Request $request): JsonResponse
    {
        $limit = $request->input('limit', 5);

        $notes = Note::where('created_by', Auth::id())
            ->orderBy('is_pinned', 'desc')
            ->orderBy('created_at', 'desc')
            ->limit($limit)
            ->get()
            ->map(function ($note) {
                return [
                    'id' => $note->id,
                    'title' => $note->title,
                    'content' => $note->content,
                    'type' => $note->type,
                    'due_date' => $note->due_date ? $note->due_date->format('Y-m-d') : null,
                    'is_pinned' => $note->is_pinned,
                    'created_at' => $note->created_at->format('M d, Y'),
                ];
            });

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

    /**
     * Store a new note
     */
    public function storeNote(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string',
            'type' => 'nullable|in:info,warning,reminder,task',
            'due_date' => 'nullable|date',
            'is_pinned' => 'nullable|boolean',
        ]);

        $note = Note::create([
            'title' => $validated['title'],
            'content' => $validated['content'],
            'type' => $validated['type'] ?? 'info',
            'due_date' => $validated['due_date'] ?? null,
            'is_pinned' => $validated['is_pinned'] ?? false,
            'created_by' => Auth::id(),
        ]);

        return response()->json([
            'success' => true,
            'note' => [
                'id' => $note->id,
                'title' => $note->title,
                'content' => $note->content,
                'type' => $note->type,
                'due_date' => $note->due_date ? $note->due_date->format('Y-m-d') : null,
                'is_pinned' => $note->is_pinned,
                'created_at' => $note->created_at->format('M d, Y'),
            ],
        ]);
    }

    /**
     * Update a note
     */
    public function updateNote(Request $request, Note $note): JsonResponse
    {
        // Check if user owns this note
        if ($note->created_by !== Auth::id()) {
            return response()->json([
                'success' => false,
                'message' => 'Unauthorized',
            ], 403);
        }

        $validated = $request->validate([
            'title' => 'sometimes|required|string|max:255',
            'content' => 'sometimes|required|string',
            'type' => 'sometimes|in:info,warning,reminder,task',
            'due_date' => 'nullable|date',
            'is_pinned' => 'sometimes|boolean',
        ]);

        $note->update($validated);

        return response()->json([
            'success' => true,
            'note' => [
                'id' => $note->id,
                'title' => $note->title,
                'content' => $note->content,
                'type' => $note->type,
                'due_date' => $note->due_date ? $note->due_date->format('Y-m-d') : null,
                'is_pinned' => $note->is_pinned,
                'created_at' => $note->created_at->format('M d, Y'),
            ],
        ]);
    }

    /**
     * Delete a note
     */
    public function deleteNote(Note $note): JsonResponse
    {
        // Check if user owns this note
        if ($note->created_by !== Auth::id()) {
            return response()->json([
                'success' => false,
                'message' => 'Unauthorized',
            ], 403);
        }

        $note->delete();

        return response()->json([
            'success' => true,
            'message' => 'Note deleted successfully',
        ]);
    }

    /**
     * Get chart data for revenue vs expenses
     */
    public function getChartData(Request $request): JsonResponse
    {
        $monthsCount = $request->input('months', 6); // Default to 6 months
        $monthsCount = max(1, min(12, (int) $monthsCount)); // Limit between 1 and 12 months

        $monthlyRevenue = [];
        $monthlyExpenses = [];
        $months = [];

        for ($i = $monthsCount - 1; $i >= 0; $i--) {
            $date = now()->subMonths($i);
            $months[] = $date->format('M');

            $monthlyRevenue[] = \App\Models\Invoice::whereYear('created_at', $date->year)
                ->whereMonth('created_at', $date->month)
                ->where('status', 'paid')
                ->sum('total');

            try {
                $monthlyExpenses[] = \App\Models\Expense::whereYear('expense_date', $date->year)
                    ->whereMonth('expense_date', $date->month)
                    ->where('status', 'approved')
                    ->sum('amount') ?? 0;
            } catch (\Exception $e) {
                $monthlyExpenses[] = 0;
            }
        }

        $maxRevenue = max($monthlyRevenue ?: [1]);
        $maxExpense = max($monthlyExpenses ?: [1]);
        $maxValue = max($maxRevenue, $maxExpense);
        if ($maxValue == 0) {
            $maxValue = 1;
        }

        // Calculate percentages for each bar
        $chartData = [];
        foreach ($months as $index => $month) {
            $revenueHeight = ($monthlyRevenue[$index] ?? 0) / $maxValue * 100;
            $expenseHeight = ($monthlyExpenses[$index] ?? 0) / $maxValue * 100;

            $chartData[] = [
                'month' => $month,
                'revenue' => $monthlyRevenue[$index] ?? 0,
                'expense' => $monthlyExpenses[$index] ?? 0,
                'revenueHeight' => max($revenueHeight, 5), // Minimum 5% for visibility
                'expenseHeight' => max($expenseHeight, 5),
                'revenueFormatted' => number_format($monthlyRevenue[$index] ?? 0, 2),
                'expenseFormatted' => number_format($monthlyExpenses[$index] ?? 0, 2),
            ];
        }

        return response()->json([
            'success' => true,
            'data' => $chartData,
            'maxValue' => $maxValue,
            'maxValueFormatted' => number_format($maxValue, 2),
        ]);
    }
}
