<?php

namespace App\Services;

use App\Models\Account;
use App\Models\Voucher;
use App\Models\Party;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

class AccountService
{
    public function getAccounts()
    {
        return Account::active()->get()->map(function ($account) {
            $account->balance = $account->balance;
            return $account;
        });
    }

    public function getCashBook($request)
    {
        $account = Account::where('type', 'cash')->firstOrFail();
        return $this->getAccountLedger($account, $request);
    }

    public function getBankBook($request)
    {
        $account = Account::where('type', 'bank')->first();
        if (! $account) return collect();
        return $this->getAccountLedger($account, $request);
    }

    public function getAccountLedger(Account $account, $request = null)
    {
        $from = $request?->from_date ?? Carbon::now()->startOfMonth()->toDateString();
        $to   = $request?->to_date   ?? Carbon::today()->toDateString();

        $opening = $account->opening_balance
            + (float) Voucher::where('account_id', $account->id)
                ->whereDate('voucher_date', '<', $from)
                ->where('type', 'receipt')
                ->sum('amount')
            - (float) Voucher::where('account_id', $account->id)
                ->whereDate('voucher_date', '<', $from)
                ->where('type', 'payment')
                ->sum('amount');

        $entries = Voucher::with('party')
            ->where('account_id', $account->id)
            ->whereBetween('voucher_date', [$from, $to])
            ->orderBy('voucher_date')
            ->orderBy('id')
            ->get()
            ->map(fn ($v) => (object) [
                'id'          => $v->id,
                'date'        => $v->voucher_date,
                'voucher_no'  => $v->voucher_no,
                'party'       => $v->party?->name,
                'description' => $v->description,
                'receipt'     => $v->type === 'receipt' ? $v->amount : 0,
                'payment'     => $v->type === 'payment' ? $v->amount : 0,
                'mode'        => $v->mode,
                'balance'     => 0, // computed below
            ]);

        $running = $opening;
        $entries = $entries->map(function ($e) use (&$running) {
            $running += $e->receipt - $e->payment;
            $e->balance = $running;
            return $e;
        });

        return [
            'account' => $account,
            'opening' => $opening,
            'entries' => $entries,
            'total_receipt' => $entries->sum('receipt'),
            'total_payment' => $entries->sum('payment'),
            'closing' => $running,
            'from'    => $from,
            'to'      => $to,
        ];
    }

    public function createReceipt(array $data): Voucher
    {
        return DB::transaction(function () use ($data) {
            $voucher = Voucher::create([
                'type'         => 'receipt',
                'voucher_date' => $data['voucher_date'] ?? today(),
                'account_id'   => $data['account_id'],
                'party_id'     => $data['party_id'],
                'amount'       => $data['amount'],
                'mode'         => $data['mode'] ?? 'cash',
                'cheque_no'    => $data['cheque_no'] ?? null,
                'cheque_date'  => $data['cheque_date'] ?? null,
                'description'   => $data['description'] ?? null,
                'created_by'   => auth()->id(),
            ]);

            // Update sale due if linked
            if (! empty($data['sale_id'])) {
                $sale = \App\Models\Sale::find($data['sale_id']);
                if ($sale) {
                    $sale->increment('paid_amount', $data['amount']);
                }
            }

            return $voucher;
        });
    }

    public function createPayment(array $data): Voucher
    {
        return DB::transaction(function () use ($data) {
            $voucher = Voucher::create([
                'type'         => 'payment',
                'voucher_date' => $data['voucher_date'] ?? today(),
                'account_id'   => $data['account_id'],
                'party_id'     => $data['party_id'],
                'amount'       => $data['amount'],
                'mode'         => $data['mode'] ?? 'cash',
                'cheque_no'    => $data['cheque_no'] ?? null,
                'cheque_date'  => $data['cheque_date'] ?? null,
                'description'   => $data['description'] ?? null,
                'created_by'   => auth()->id(),
            ]);

            if (! empty($data['purchase_id'])) {
                $purchase = \App\Models\Purchase::find($data['purchase_id']);
                if ($purchase) {
                    $purchase->increment('paid_amount', $data['amount']);
                }
            }

            return $voucher;
        });
    }

    public function getDailyTransactions($request)
    {
        $date = $request?->date ?? Carbon::today()->toDateString();

        return [
            'purchases'     => \App\Models\Purchase::with(['party', 'items.yarn'])
                                ->whereDate('purchase_date', $date)->get(),
            'sales'         => \App\Models\Sale::with(['party', 'items.yarn'])
                                ->whereDate('sales_date', $date)->get(),
            'purchase_returns' => collect(),
            'sale_returns'    => collect(),
            'date'          => $date,
        ];
    }
}
