<?php

namespace App\Services;

use App\Models\Sale;
use App\Models\SaleItem;
use App\Models\StockLedger;
use Illuminate\Support\Facades\DB;

class SaleService
{
    public function getFiltered($request)
    {
        $query = Sale::with(['party', 'items.yarn', 'creator']);

        if ($from = $request->from_date) {
            $query->whereDate('sales_date', '>=', $from);
        }
        if ($to = $request->to_date) {
            $query->whereDate('sales_date', '<=', $to);
        }
        if ($customer = $request->party_id) {
            $query->where('party_id', $customer);
        }
        if ($search = $request->search) {
            $query->where(function ($q) use ($search) {
                $q->where('voucher_no', 'like', "%{$search}%")
                  ->orWhere('invoice_no', 'like', "%{$search}%")
                  ->orWhereHas('party', fn ($q2) => $q2->where('name', 'like', "%{$search}%"));
            });
        }

        return $query->latest('sales_date')->paginate(20)->withQueryString();
    }

    public function create(array $data): Sale
    {
        return DB::transaction(function () use ($data) {
            $subtotal = collect($data['items'])->sum(fn ($i) => $i['quantity'] * $i['rate']);

            $sale = Sale::create([
                'party_id'     => $data['party_id'],
                'sales_date'   => $data['sales_date'],
                'invoice_no'   => $data['invoice_no'] ?? null,
                'subtotal'     => $subtotal,
                'labour_charge'=> $data['labour_charge'] ?? 0,
                'car_rent'     => $data['car_rent'] ?? 0,
                'other_charge' => $data['other_charge'] ?? 0,
                'discount'     => $data['discount'] ?? 0,
                'grand_total'  => $subtotal
                                + ($data['labour_charge'] ?? 0)
                                + ($data['car_rent'] ?? 0)
                                + ($data['other_charge'] ?? 0)
                                - ($data['discount'] ?? 0),
                'paid_amount'  => $data['paid_amount'] ?? 0,
                'remarks'      => $data['remarks'] ?? null,
                'created_by'   => auth()->id(),
            ]);

            foreach ($data['items'] as $item) {
                SaleItem::create([
                    'sale_id'   => $sale->id,
                    'yarn_id'   => $item['yarn_id'],
                    'lot_no'    => $item['lot_no'] ?? null,
                    'bags'      => $item['bags'] ?? 0,
                    'quantity'  => $item['quantity'],
                    'unit'      => $item['unit'] ?? 'Kg',
                    'rate'      => $item['rate'],
                    'amount'    => $item['quantity'] * $item['rate'],
                ]);
            }

            // Stock ledger
            foreach ($sale->items as $item) {
                StockLedger::create([
                    'transaction_date' => $sale->sales_date,
                    'yarn_id'         => $item->yarn_id,
                    'lot_no'          => $item->lot_no,
                    'type'            => 'sale',
                    'reference_type'  => Sale::class,
                    'reference_id'    => $sale->id,
                    'voucher_no'      => $sale->voucher_no,
                    'in_qty'          => 0,
                    'out_qty'         => $item->quantity,
                    'rate'            => $item->rate,
                    'value'           => $item->amount,
                    'remarks'         => 'Sale to ' . $sale->party->name,
                ]);
            }

            // Receipt voucher if payment received
            if (($data['paid_amount'] ?? 0) > 0 && ! empty($data['account_id'])) {
                \App\Models\Voucher::create([
                    'type'         => 'receipt',
                    'voucher_date' => $sale->sales_date,
                    'account_id'   => $data['account_id'],
                    'party_id'     => $sale->party_id,
                    'amount'       => $data['paid_amount'],
                    'mode'         => $data['payment_mode'] ?? 'cash',
                    'description'  => 'Receipt for ' . $sale->voucher_no,
                    'created_by'   => auth()->id(),
                ]);
            }

            return $sale->fresh(['items.yarn', 'party']);
        });
    }

    public function update(Sale $sale, array $data): Sale
    {
        return DB::transaction(function () use ($sale, $data) {
            StockLedger::where('reference_type', Sale::class)->where('reference_id', $sale->id)->delete();

            $subtotal = collect($data['items'])->sum(fn ($i) => $i['quantity'] * $i['rate']);

            $sale->update([
                'party_id'    => $data['party_id'],
                'sales_date'  => $data['sales_date'],
                'invoice_no'  => $data['invoice_no'] ?? null,
                'subtotal'    => $subtotal,
                'labour_charge' => $data['labour_charge'] ?? 0,
                'car_rent'    => $data['car_rent'] ?? 0,
                'other_charge'=> $data['other_charge'] ?? 0,
                'discount'    => $data['discount'] ?? 0,
                'grand_total' => $subtotal + ($data['labour_charge'] ?? 0) + ($data['car_rent'] ?? 0) + ($data['other_charge'] ?? 0) - ($data['discount'] ?? 0),
                'paid_amount' => $data['paid_amount'] ?? 0,
                'remarks'     => $data['remarks'] ?? null,
            ]);

            $sale->items()->delete();
            foreach ($data['items'] as $item) {
                SaleItem::create([
                    'sale_id'   => $sale->id,
                    'yarn_id'   => $item['yarn_id'],
                    'lot_no'    => $item['lot_no'] ?? null,
                    'bags'      => $item['bags'] ?? 0,
                    'quantity'  => $item['quantity'],
                    'unit'      => $item['unit'] ?? 'Kg',
                    'rate'      => $item['rate'],
                    'amount'    => $item['quantity'] * $item['rate'],
                ]);
            }

            foreach ($sale->items as $item) {
                StockLedger::create([
                    'transaction_date' => $sale->sales_date,
                    'yarn_id'         => $item->yarn_id,
                    'lot_no'          => $item->lot_no,
                    'type'            => 'sale',
                    'reference_type'  => Sale::class,
                    'reference_id'    => $sale->id,
                    'voucher_no'      => $sale->voucher_no,
                    'in_qty'          => 0,
                    'out_qty'         => $item->quantity,
                    'rate'            => $item->rate,
                    'value'           => $item->amount,
                ]);
            }

            return $sale->fresh(['items.yarn', 'party']);
        });
    }

    public function getTotals($sales): array
    {
        return [
            'count'       => $sales->count(),
            'subtotal'    => $sales->sum('subtotal'),
            'grand_total' => $sales->sum('grand_total'),
            'paid'        => $sales->sum('paid_amount'),
            'due'         => $sales->sum('due_amount'),
        ];
    }
}
