<?php

namespace App\Http\Controllers\Franchise;

use App\Exports\SimpleArrayExport;
use App\Http\Controllers\Controller;
use App\Models\Franchise;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\FranchiseTransaction;
use App\Models\Product;
use App\Models\FranchiseStock;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Facades\Excel;

class ReportController extends Controller
{
    public function daily(Request $request): View|\Symfony\Component\HttpFoundation\BinaryFileResponse
    {
        $franchise = $this->getFranchise();
        $from = $request->input('from', now()->startOfMonth()->toDateString());
        $to = $request->input('to', now()->toDateString());

        $orders = Order::query()
            ->where('franchise_id', $franchise?->id)
            ->whereDate('approved_at', '>=', $from)
            ->whereDate('approved_at', '<=', $to)
            ->whereIn('status', ['approved', 'delivered', 'dispatched'])
            ->with('user')
            ->latest('approved_at')
            ->get();

        $rows = $orders->map(fn ($order) => [
            optional($order->approved_at)->toDateString(),
            $order->order_number,
            $order->user?->member_code,
            $order->total,
            $order->total_bv,
            $order->payment_method,
        ])->all();

        return $this->exportOrView($request, 'franchise.reports.daily', 'daily-sales',
            ['Date', 'Order', 'Member', 'Total', 'BV', 'Payment'],
            $rows,
            compact('orders', 'from', 'to')
        );
    }

    public function products(Request $request): View|\Symfony\Component\HttpFoundation\BinaryFileResponse
    {
        $franchise = $this->getFranchise();
        $from = $request->input('from', now()->startOfMonth()->toDateString());
        $to = $request->input('to', now()->toDateString());

        $rows = DB::table('order_items as oi')
            ->join('orders as o', 'o.id', '=', 'oi.order_id')
            ->where('o.franchise_id', $franchise?->id)
            ->whereDate('o.approved_at', '>=', $from)
            ->whereDate('o.approved_at', '<=', $to)
            ->whereIn('o.status', ['approved', 'delivered', 'dispatched'])
            ->groupBy('oi.product_id', 'oi.product_name')
            ->select([
                'oi.product_name',
                DB::raw('SUM(oi.quantity) as total_qty'),
                DB::raw('SUM(oi.line_total) as total_sales'),
                DB::raw('SUM(oi.line_bv) as total_bv'),
            ])
            ->get();

        $mapped = $rows->map(fn ($row) => [
            $row->product_name,
            $row->total_qty,
            $row->total_sales,
            $row->total_bv,
        ])->all();

        return $this->exportOrView($request, 'franchise.reports.products', 'product-report',
            ['Product', 'Qty', 'Sales', 'BV'],
            $mapped,
            compact('rows', 'from', 'to')
        );
    }

    public function bv(Request $request): View|\Symfony\Component\HttpFoundation\BinaryFileResponse
    {
        $franchise = $this->getFranchise();
        $from = $request->input('from', now()->startOfMonth()->toDateString());
        $to = $request->input('to', now()->toDateString());

        $rows = Order::query()
            ->where('franchise_id', $franchise?->id)
            ->whereDate('approved_at', '>=', $from)
            ->whereDate('approved_at', '<=', $to)
            ->whereIn('status', ['approved', 'delivered', 'dispatched'])
            ->get()
            ->groupBy(fn ($order) => optional($order->approved_at)->toDateString())
            ->map(fn ($group, $date) => [$date, $group->sum('total_bv')])
            ->values()
            ->all();

        return $this->exportOrView($request, 'franchise.reports.bv', 'bv-report', ['Date', 'BV'], $rows, compact('rows', 'from', 'to'));
    }

    public function commission(Request $request): View|\Symfony\Component\HttpFoundation\BinaryFileResponse
    {
        $franchise = $this->getFranchise();
        $rows = FranchiseTransaction::query()
            ->where('franchise_id', $franchise?->id)
            ->whereIn('transaction_type', ['commission_credit', 'commission_debit'])
            ->latest('id')
            ->get();

        $mapped = $rows->map(fn ($row) => [
            optional($row->transacted_at)->format('Y-m-d'),
            $row->transaction_type,
            $row->amount,
            $row->reference,
        ])->all();

        return $this->exportOrView($request, 'franchise.reports.commission', 'commission-report',
            ['Date', 'Type', 'Amount', 'Reference'],
            $mapped,
            compact('rows')
        );
    }

    public function stock(Request $request): View|\Symfony\Component\HttpFoundation\BinaryFileResponse
    {
        $franchise = $this->getFranchise();
        $rows = DB::table('franchise_stocks as fs')
            ->join('products as p', 'p.id', '=', 'fs.product_id')
            ->where('fs.franchise_id', $franchise?->id)
            ->select(['p.name', 'p.sku', 'fs.quantity', 'p.dp_price', 'p.bv'])
            ->orderBy('p.name')
            ->get();

        $mapped = $rows->map(fn ($row) => [
            $row->name,
            $row->sku,
            $row->quantity,
            $row->dp_price,
            $row->bv,
        ])->all();

        return $this->exportOrView($request, 'franchise.reports.stock', 'stock-report',
            ['Product', 'SKU', 'Qty', 'DP', 'BV'],
            $mapped,
            compact('rows')
        );
    }

    public function damage(Request $request): View|\Symfony\Component\HttpFoundation\BinaryFileResponse
    {
        $franchise = $this->getFranchise();
        $rows = FranchiseTransaction::query()
            ->where('franchise_id', $franchise?->id)
            ->where('transaction_type', 'damage')
            ->latest('id')
            ->get();

        $mapped = $rows->map(fn ($row) => [
            optional($row->transacted_at)->format('Y-m-d'),
            $row->product_id,
            $row->quantity,
            $row->reference,
        ])->all();

        return $this->exportOrView($request, 'franchise.reports.damage', 'damage-report',
            ['Date', 'Product', 'Qty', 'Reference'],
            $mapped,
            compact('rows')
        );
    }

    private function getFranchise(): ?Franchise
    {
        return Franchise::query()->where('created_by', auth()->id())->first();
    }

    /**
     * @param  array<int, string>  $headings
     * @param  array<int, array<int, mixed>>  $rows
     * @param  array<string, mixed>  $viewData
     */
    private function exportOrView(Request $request, string $view, string $filename, array $headings, array $rows, array $viewData): View|\Symfony\Component\HttpFoundation\BinaryFileResponse
    {
        if ($request->get('export') === 'excel') {
            return Excel::download(new SimpleArrayExport($rows, $headings), $filename.'.xlsx');
        }

        if ($request->get('export') === 'pdf') {
            $pdf = Pdf::loadView('franchise.reports.pdf', [
                'headings' => $headings,
                'rows' => $rows,
                'title' => $filename,
            ]);

            return $pdf->download($filename.'.pdf');
        }

        return view($view, $viewData);
    }
}

