<?php

namespace App\Http\Controllers\Admin\Finance\Report;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Carbon\Carbon;
use App\Models\MerchantInvoice;
use App\Models\MerchantPayment;
use App\Models\Expense;
use App\Models\Parcel;
use App\Models\ReportSchedule;

class ReportController extends Controller
{
    public function financial()
    {
        return view('admin.finance.reports.financial');
    }

    public function operational()
    {
        return view('admin.finance.reports.operational');
    }

    public function custom()
    {
        return view('admin.finance.reports.custom');
    }

    public function export()
    {
        return view('admin.finance.reports.export');
    }

    public function dashboard()
    {
        return view('admin.finance.reports.dashboard');
    }

    public function schedule()
    {
        $schedules = ReportSchedule::latest()->paginate(15);
        return view('admin.finance.reports.schedule', compact('schedules'));
    }

    public function financialData(Request $request)
    {
        $start = $request->input('start_date');
        $end = $request->input('end_date');

        $invoiceQuery = MerchantInvoice::query();
        $paymentQuery = MerchantPayment::query();
        $expenseQuery = Expense::query();

        if ($start) {
            $invoiceQuery->where('created_at', '>=', $start);
            $paymentQuery->where('created_at', '>=', $start);
            $expenseQuery->where('created_at', '>=', $start);
        }
        if ($end) {
            $invoiceQuery->where('created_at', '<=', $end);
            $paymentQuery->where('created_at', '<=', $end);
            $expenseQuery->where('created_at', '<=', $end);
        }

        $data = [
            'total_invoices' => (int) $invoiceQuery->count(),
            'outstanding_amount' => (float) (clone $invoiceQuery)->where('status', '!=', 'paid')->sum('total_amount'),
            'total_payments' => (float) $paymentQuery->sum('amount'),
            'approved_expenses' => (float) (clone $expenseQuery)->where('status', 'approved')->sum('amount'),
            'top_merchants' => MerchantInvoice::selectRaw('seller_id, COUNT(*) as invoice_count, SUM(total_amount) as total_billed')
                ->groupBy('seller_id')
                ->orderByDesc('total_billed')
                ->take(5)
                ->get(),
        ];

        return response()->json($data);
    }

    public function operationalData(Request $request)
    {
        $start = $request->input('start_date');
        $end = $request->input('end_date');
        $query = Parcel::query();
        if ($start) {
            $query->where('created_at', '>=', $start);
        }
        if ($end) {
            $query->where('created_at', '<=', $end);
        }

        $data = [
            'total_parcels' => (int) $query->count(),
            'delivered' => (int) (clone $query)->where('status', 'Delivered')->count(),
            'in_transit' => (int) (clone $query)->where('status', 'In Transit')->count(),
            'pending' => (int) (clone $query)->where('status', 'Pending')->count(),
            'returned' => (int) (clone $query)->where('status', 'Returned')->count(),
            // Use updated_at for delivered timeline since delivered_at column doesn't exist
            'daily_deliveries' => Parcel::selectRaw('DATE(updated_at) as day, COUNT(*) as count')
                ->where('status', 'Delivered')
                ->when($start, fn($q) => $q->where('updated_at', '>=', $start))
                ->when($end, fn($q) => $q->where('updated_at', '<=', $end))
                ->groupBy('day')
                ->orderBy('day')
                ->take(14)
                ->get(),
        ];

        return response()->json($data);
    }

    public function customData(Request $request)
    {
        $entity = $request->input('entity', 'expenses');
        $limit = (int) $request->input('limit', 10);
        $data = [];
        switch ($entity) {
            case 'invoices':
                $data = MerchantInvoice::latest()->take($limit)->get();
                break;
            case 'payments':
                $data = MerchantPayment::latest()->take($limit)->get();
                break;
            case 'parcels':
                $data = Parcel::latest()->with(['seller', 'rider'])->take($limit)->get();
                break;
            case 'expenses':
            default:
                $data = Expense::latest()->take($limit)->get();
                break;
        }

        return response()->json(['entity' => $entity, 'items' => $data]);
    }

    public function exportData(Request $request)
    {
        $type = $request->input('type'); // financial, operational, custom
        $format = $request->input('format', 'csv');
        $filename = $type . '_report_' . now()->format('Y_m_d_His') . '.' . $format;

        if ($format !== 'csv') {
            return response()->json(['message' => 'Only CSV export is supported currently.'], 422);
        }

        // Build dataset
        $rows = [];
        if ($type === 'financial') {
            $invoices = MerchantInvoice::latest()->take(100)->get();
            $rows[] = ['Invoice ID', 'Seller', 'Status', 'Total Amount', 'Created At'];
            foreach ($invoices as $inv) {
                $rows[] = [$inv->id, $inv->seller_id, $inv->status, $inv->total_amount, $inv->created_at];
            }
        } elseif ($type === 'operational') {
            $parcels = Parcel::latest()->take(100)->get();
            $rows[] = ['Tracking', 'Status', 'Seller', 'Rider', 'COD Amount', 'Created At'];
            foreach ($parcels as $p) {
                $rows[] = [$p->tracking_id, $p->status, $p->seller_id, $p->assigned_rider_id, $p->cod_amount, $p->created_at];
            }
        } else { // custom default to expenses
            $expenses = Expense::latest()->take(100)->get();
            $rows[] = ['Expense ID', 'Category', 'Amount', 'Status', 'Created At'];
            foreach ($expenses as $e) {
                $rows[] = [$e->id, $e->category ?? 'N/A', $e->amount, $e->status, $e->created_at];
            }
        }

        $csv = '';
        foreach ($rows as $row) {
            $csv .= implode(',', array_map(function ($v) {
                $v = (string) $v;
                $v = str_replace(["\r", "\n"], ' ', $v);
                if (str_contains($v, ',')) {
                    $v = '"' . str_replace('"', '""', $v) . '"';
                }
                return $v;
            }, $row)) . "\n";
        }

        return response($csv, 200, [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
        ]);
    }

    public function dashboardData(Request $request)
    {
        // Optional date range (inclusive). Defaults to last 7 days.
        $startInput = $request->query('start');
        $endInput = $request->query('end');

        try {
            $start = $startInput ? Carbon::parse($startInput)->startOfDay() : now()->subDays(6)->startOfDay();
        } catch (\Exception $e) {
            $start = now()->subDays(6)->startOfDay();
        }

        try {
            $end = $endInput ? Carbon::parse($endInput)->endOfDay() : now()->endOfDay();
        } catch (\Exception $e) {
            $end = now()->endOfDay();
        }

        if ($end->lt($start)) {
            [$start, $end] = [$end->copy()->startOfDay(), $start->copy()->endOfDay()];
        }

        $days = $start->diffInDays($end) + 1; // inclusive
        $labels = collect(range(0, $days - 1))->map(function ($i) use ($start) {
            return $start->copy()->addDays($i)->toDateString();
        });

        // Use updated_at for delivered parcels timeline since delivered_at column doesn't exist
        $deliveries = Parcel::selectRaw('DATE(updated_at) as day, COUNT(*) as count')
            ->where('status', 'Delivered')
            ->whereDate('updated_at', '>=', $start->toDateString())
            ->whereDate('updated_at', '<=', $end->toDateString())
            ->groupBy('day')
            ->pluck('count', 'day');

        $series = $labels->map(fn($d) => (int) ($deliveries[$d] ?? 0));

        $summary = [
            'total_invoices' => (int) MerchantInvoice::count(),
            'outstanding_amount' => (float) MerchantInvoice::where('status', '!=', 'paid')->sum('total_amount'),
            'total_payments' => (float) MerchantPayment::sum('amount'),
            'approved_expenses' => (float) Expense::where('status', 'approved')->sum('amount'),
            'delivered_parcels' => (int) Parcel::where('status', 'Delivered')->count(),
        ];

        return response()->json([
            'labels' => $labels,
            'series' => $series,
            'summary' => $summary,
            'range' => [
                'start' => $start->toDateString(),
                'end' => $end->toDateString(),
            ],
        ]);
    }

    public function scheduleData()
    {
        $schedules = ReportSchedule::latest()->get();
        return response()->json(['items' => $schedules]);
    }

    public function storeSchedule(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'type' => 'required|in:financial,operational,custom',
            'format' => 'required|in:csv,xlsx,pdf',
            'frequency' => 'required|in:daily,weekly,monthly',
            'recipients' => 'nullable|string',
            'filters' => 'nullable',
            'is_active' => 'nullable|boolean',
        ]);

        $nextRun = match ($validated['frequency']) {
            'daily' => now()->addDay(),
            'weekly' => now()->addWeek(),
            'monthly' => now()->addMonth(),
            default => now()->addDay(),
        };

        ReportSchedule::create([
            'name' => $validated['name'],
            'type' => $validated['type'],
            'format' => $validated['format'],
            'frequency' => $validated['frequency'],
            'recipients' => $validated['recipients'] ?? null,
            'filters' => $request->input('filters') ? json_decode($request->input('filters'), true) : null,
            'next_run_at' => $nextRun,
            'is_active' => $request->boolean('is_active', true),
        ]);

        return redirect()->route('admin.finance.reports.schedule')->with('status', 'Report schedule created.');
    }
}
