<?php

declare(strict_types=1);

namespace App\Modules\Sales\Application\Services;

use App\Shared\Parties\PartyLedgerSupport;
use PDO;

final class PosFormService
{
    public function defaultForm(PDO $pdo): array
    {
        $warehouseId = (int)($pdo->query("SELECT id FROM warehouses WHERE is_active=1 ORDER BY id LIMIT 1")->fetchColumn() ?: 0);
        $cashboxId = current_user_cashbox_id($pdo);
        if ($cashboxId <= 0) {
            $cashboxId = (int)($pdo->query("SELECT id FROM cashboxes WHERE is_active=1 ORDER BY id LIMIT 1")->fetchColumn() ?: 0);
        }

        return [
            'invoice_date' => date('Y-m-d'),
            'warehouse_id' => $warehouseId,
            'party_id' => 0,
            'customer_id' => 0,
            'customer_label' => '',
            'party_label' => '',
            'payment_mode' => 'cash',
            'paid_amount' => 0,
            'due_amount' => 0,
            'cashbox_id' => $cashboxId,
            'received_amount' => 0,
            'change_amount' => 0,
            'discount_type' => 'VALUE',
            'discount_value' => 0,
            'discount_amount' => 0,
            'grand_total' => 0,
            'print_now' => 1,
            'notes' => '',
            'collection_note' => '',
        ];
    }

    public function oldForm(PDO $pdo): array
    {
        $form = $this->defaultForm($pdo);
        if (!empty($_SESSION['pos_form_old']) && is_array($_SESSION['pos_form_old'])) {
            $form = array_merge($form, $_SESSION['pos_form_old']);
            unset($_SESSION['pos_form_old']);
        }

        $partyId = (int)($form['party_id'] ?? $form['customer_id'] ?? 0);
        if ($partyId > 0 && empty($form['customer_label'])) {
            $party = $this->findParty($pdo, $partyId);
            if ($party) {
                $label = (string)$party['name'] . ' (' . (string)$party['code'] . ')';
                $form['customer_label'] = $label;
                $form['party_label'] = $label;
            }
        }

        return $form;
    }

    public function storeOld(array $form): void
    {
        $_SESSION['pos_form_old'] = $form;
    }

    public function clearOld(): void
    {
        unset($_SESSION['pos_form_old']);
    }

    public function fail(string $message, array $form): void
    {
        $this->storeOld($form);
        flash_set('danger', $message);
        redirect(PosRouteContext::pos());
    }

    public function walkinPartyId(PDO $pdo): int
    {
        $candidates = ['عميل نقدي POS', 'عميل نقدي', 'عميل كاش'];
        foreach ($candidates as $name) {
            $st = $pdo->prepare("SELECT id FROM parties WHERE is_active=1 AND is_customer=1 AND name=? ORDER BY id LIMIT 1");
            $st->execute([$name]);
            $id = (int)($st->fetchColumn() ?: 0);
            if ($id > 0) {
                return $id;
            }
        }

        $pdo->prepare("INSERT INTO parties (name, code, is_customer, is_supplier, is_active, created_at) VALUES (?,?,?,?,1,NOW())")
            ->execute(['عميل نقدي POS', 'POS-CASH', 1, 0]);
        $id = (int)$pdo->lastInsertId();
        PartyLedgerSupport::autoCode($pdo, $id);
        return $id;
    }

    public function applyDiscount(float $subtotal, string $type, float $value): array
    {
        $subtotal = round(max(0, $subtotal), 2);
        $type = strtoupper(trim($type));
        $value = max(0, $value);
        if ($type === 'PERCENT') {
            if ($value > 100) {
                $value = 100;
            }
            $discount = round($subtotal * ($value / 100), 2);
        } else {
            $type = 'VALUE';
            if ($value > $subtotal) {
                $value = $subtotal;
            }
            $discount = round($value, 2);
        }
        $grand = round(max(0, $subtotal - $discount), 2);
        return [$type, round($value, 2), $discount, $grand];
    }

    public function loadIndexData(PDO $pdo, PosCartService $cartService, PosSuspendedCartService $suspendedCartService): array
    {
        $warehouses = $pdo->query("SELECT id, name FROM warehouses WHERE is_active=1 ORDER BY name")->fetchAll();
        $userCashboxId = current_user_cashbox_id($pdo);
        $cashboxes = [];
        $userCashbox = null;
        if ($userCashboxId > 0) {
            $stCash = $pdo->prepare("SELECT id, name FROM cashboxes WHERE id=? AND is_active=1 LIMIT 1");
            $stCash->execute([$userCashboxId]);
            $userCashbox = $stCash->fetch();
            if ($userCashbox) {
                $cashboxes = [$userCashbox];
            }
        }
        $units = $pdo->query("SELECT id, name FROM units ORDER BY name")->fetchAll();
        $itemsQuick = $pdo->query("SELECT id, name, barcode, price FROM items WHERE is_active=1 ORDER BY name LIMIT 2000")->fetchAll();
        $form = $this->oldForm($pdo);
        $party = null;
        $partyId = (int)($form['party_id'] ?? 0);
        if ($partyId > 0) {
            $party = $this->findParty($pdo, $partyId);
        }
        $snap = $cartService->snapshot($pdo);

        return [
            'items' => $itemsQuick,
            'units' => $units,
            'warehouses' => $warehouses,
            'cashboxes' => $cashboxes,
            'userCashbox' => $userCashbox,
            'userCashboxId' => $userCashboxId,
            'suspended_carts' => $suspendedCartService->allForDisplay($pdo, $cartService),
            'cart' => $snap['cart'],
            'cart_lines' => $snap['cart_lines'],
            'cart_total' => (float)$snap['cart_total'],
            'cart_count' => (float)$snap['cart_count'],
            'form' => $form,
            'party' => $party,
            'customer' => $party,
            'isUserCashboxActive' => (bool)$userCashbox,
        ];
    }

    public function findParty(PDO $pdo, int $partyId): ?array
    {
        $st = $pdo->prepare("SELECT id, name, COALESCE(code, CONCAT('P',LPAD(id,5,'0'))) code, phone FROM parties WHERE id=? LIMIT 1");
        $st->execute([$partyId]);
        $row = $st->fetch();
        return is_array($row) ? $row : null;
    }
}
