<?php

declare(strict_types=1);

namespace App\Modules\Sales\Application\Services;

use App\Services\PrintSettingsService;
use PDO;
use Throwable;

final class PosActionService
{
    public function __construct(
        private ?PosFormService $forms = null,
        private ?PosCartService $cartService = null,
        private ?PosSuspendedCartService $suspendedCartService = null,
        private ?PosCheckoutService $checkoutService = null,
    ) {
        $this->forms ??= new PosFormService();
        $this->cartService ??= new PosCartService();
        $this->suspendedCartService ??= new PosSuspendedCartService();
        $this->checkoutService ??= new PosCheckoutService();
    }

    public function handle(PDO $pdo): void
    {
        $action = $_POST['action'] ?? ($_GET['action'] ?? '');
        $isAjax = (($_POST['ajax'] ?? $_GET['ajax'] ?? '') === '1');

        if (in_array($action, ['add', 'barcode', 'update', 'remove', 'checkout'], true) && $_SERVER['REQUEST_METHOD'] === 'POST') {
            verify_csrf();
        }

        switch ($action) {
            case 'add':
                if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                    $this->add($pdo, $isAjax);
                }
                break;
            case 'barcode':
                if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                    $this->barcode($pdo, $isAjax);
                }
                break;
            case 'update':
                if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                    $this->update($pdo, $isAjax);
                }
                break;
            case 'inc':
            case 'dec':
                if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                    $this->adjust($pdo, $action, $isAjax);
                }
                break;
            case 'remove':
                $this->remove($pdo, $isAjax);
                break;
            case 'clear':
                $this->clear($pdo, $isAjax);
                break;
            case 'suspend':
                if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                    verify_csrf();
                    $this->suspend($pdo);
                }
                break;
            case 'resume':
                $this->resume($pdo);
                break;
            case 'delete_suspend':
                $this->deleteSuspend();
                break;
            case 'checkout':
                if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                    $this->checkout($pdo);
                }
                break;
        }
    }

    private function redirect(): void
    {
        redirect(PosRouteContext::pos());
    }

    private function add(PDO $pdo, bool $isAjax): void
    {
        $itemId = (int)($_POST['item_id'] ?? 0);
        $qty = (float)($_POST['qty'] ?? 1);
        $unitId = (int)($_POST['unit_id'] ?? 0);
        $unitId = $unitId > 0 ? $unitId : null;

        if ($itemId <= 0) {
            if ($isAjax) {
                $this->cartService->json($pdo, false, 'اختر الصنف أولًا.', 422);
            }
            flash_set('danger', 'اختر الصنف أولًا.');
            $this->redirect();
        }
        if ($qty <= 0) {
            if ($isAjax) {
                $this->cartService->json($pdo, false, 'الكمية يجب أن تكون أكبر من صفر.', 422);
            }
            flash_set('danger', 'الكمية يجب أن تكون أكبر من صفر.');
            $this->redirect();
        }

        $factor = item_unit_factor($pdo, $itemId, $unitId);
        $baseQty = $qty * $factor;
        $currentQty = $this->cartService->entryQty($_SESSION['cart'][$itemId] ?? 0);
        $this->cartService->setItem($itemId, $currentQty + $baseQty);
        if ($isAjax) {
            $this->cartService->json($pdo, true, 'تمت إضافة الصنف إلى السلة.');
        }
        $this->redirect();
    }

    private function barcode(PDO $pdo, bool $isAjax): void
    {
        $barcode = trim((string)($_POST['barcode'] ?? ''));
        $qty = (float)($_POST['qty'] ?? 1);
        if ($barcode === '') {
            if ($isAjax) {
                $this->cartService->json($pdo, false, 'امسح الباركود أو اكتبه أولًا.', 422);
            }
            flash_set('danger', 'امسح الباركود أو اكتبه أولًا.');
            $this->redirect();
        }
        if ($qty <= 0) {
            if ($isAjax) {
                $this->cartService->json($pdo, false, 'الكمية يجب أن تكون أكبر من صفر.', 422);
            }
            flash_set('danger', 'الكمية يجب أن تكون أكبر من صفر.');
            $this->redirect();
        }

        [$id, $unitId, $factor] = lookup_by_barcode($pdo, $barcode);
        if ($id <= 0) {
            if ($isAjax) {
                $this->cartService->json($pdo, false, 'هذا الباركود غير موجود.', 404);
            }
            flash_set('danger', 'هذا الباركود غير موجود.');
            $this->redirect();
        }

        $baseQty = $qty * (($factor > 0) ? $factor : 1);
        $currentQty = $this->cartService->entryQty($_SESSION['cart'][$id] ?? 0);
        $this->cartService->setItem((int)$id, $currentQty + $baseQty);
        if ($isAjax) {
            $this->cartService->json($pdo, true, 'تمت إضافة الصنف بالباركود.');
        }
        $this->redirect();
    }

    private function update(PDO $pdo, bool $isAjax): void
    {
        $itemId = (int)($_POST['item_id'] ?? 0);
        $qty = (float)($_POST['qty'] ?? 0);
        if ($itemId > 0) {
            $entry = $this->cartService->normalizeEntry($_SESSION['cart'][$itemId] ?? 0);
            $this->cartService->setItem($itemId, $qty, (string)$entry['discount_type'], (float)$entry['discount_value']);
        }
        if ($isAjax) {
            $this->cartService->json($pdo, true, 'تم تحديث الكمية.');
        }
        $this->redirect();
    }

    private function adjust(PDO $pdo, string $action, bool $isAjax): void
    {
        $itemId = (int)($_POST['item_id'] ?? ($_GET['item_id'] ?? 0));
        $step = (float)($_POST['step'] ?? ($_GET['step'] ?? 1));
        if ($step <= 0) {
            $step = 1;
        }
        if ($itemId > 0 && isset($_SESSION['cart'][$itemId])) {
            $entry = $this->cartService->normalizeEntry($_SESSION['cart'][$itemId]);
            $delta = ($action === 'inc') ? $step : -$step;
            $this->cartService->setItem($itemId, (float)$entry['qty'] + $delta, (string)$entry['discount_type'], (float)$entry['discount_value']);
        }
        if ($isAjax) {
            $this->cartService->json($pdo, true, 'تم تحديث الكمية.');
        }
        $this->redirect();
    }

    private function remove(PDO $pdo, bool $isAjax): void
    {
        $itemId = (int)($_POST['item_id'] ?? ($_GET['item_id'] ?? 0));
        if ($itemId > 0) {
            $this->cartService->removeItem($itemId);
        }
        if ($isAjax) {
            $this->cartService->json($pdo, true, 'تم حذف الصنف من السلة.');
        }
        $this->redirect();
    }

    private function clear(PDO $pdo, bool $isAjax): void
    {
        $this->cartService->clear();
        if ($isAjax) {
            $this->cartService->json($pdo, true, 'تم تفريغ السلة.');
        }
        $this->redirect();
    }

    private function suspend(PDO $pdo): void
    {
        if (!$this->cartService->all()) {
            $this->forms->fail('السلة فارغة، لا يوجد ما يمكن تعليقه.', array_merge($this->forms->defaultForm($pdo), [
                'party_id' => (int)($_POST['party_id'] ?? ($_POST['customer_id'] ?? 0)),
                'customer_id' => (int)($_POST['party_id'] ?? ($_POST['customer_id'] ?? 0)),
                'customer_label' => trim((string)($_POST['customer_label'] ?? '')),
                'warehouse_id' => (int)($_POST['warehouse_id'] ?? 0),
                'received_amount' => (float)($_POST['received_amount'] ?? 0),
                'discount_type' => (string)($_POST['discount_type'] ?? 'VALUE'),
                'discount_value' => (float)($_POST['discount_value'] ?? 0),
                'notes' => trim((string)($_POST['notes'] ?? '')),
                'collection_note' => trim((string)($_POST['collection_note'] ?? '')),
            ]));
        }

        $entryId = $this->suspendedCartService->suspendCurrentCart($this->cartService, [
            'party_id' => (int)($_POST['party_id'] ?? ($_POST['customer_id'] ?? 0)),
            'customer_id' => (int)($_POST['party_id'] ?? ($_POST['customer_id'] ?? 0)),
            'customer_label' => trim((string)($_POST['customer_label'] ?? '')),
            'warehouse_id' => (int)($_POST['warehouse_id'] ?? 0),
            'received_amount' => (float)($_POST['received_amount'] ?? 0),
            'discount_type' => (string)($_POST['discount_type'] ?? 'VALUE'),
            'discount_value' => (float)($_POST['discount_value'] ?? 0),
            'notes' => trim((string)($_POST['notes'] ?? '')),
            'collection_note' => trim((string)($_POST['collection_note'] ?? '')),
            'print_now' => (int)($_POST['print_now'] ?? 1),
        ]);
        $this->forms->storeOld($this->forms->defaultForm($pdo));
        flash_set('success', 'تم تعليق السلة بنجاح.');
        $this->redirect();
    }

    private function resume(PDO $pdo): void
    {
        $sid = (string)($_GET['sid'] ?? '');
        if ($sid !== '') {
            $entryForm = $this->suspendedCartService->resumeIntoCart($sid, $this->cartService);
            if ($entryForm !== null) {
                $this->forms->storeOld(array_merge($this->forms->defaultForm($pdo), $entryForm));
                flash_set('success', 'تم استرجاع السلة المعلقة.');
            }
        }
        $this->redirect();
    }

    private function deleteSuspend(): void
    {
        $sid = (string)($_GET['sid'] ?? '');
        if ($sid !== '') {
            $this->suspendedCartService->delete($sid);
            flash_set('success', 'تم حذف السلة المعلقة.');
        }
        $this->redirect();
    }

    private function checkout(PDO $pdo): void
    {
        $pageData = $this->forms->loadIndexData($pdo, $this->cartService, $this->suspendedCartService);
        $form = [
            'invoice_date' => date('Y-m-d'),
            'warehouse_id' => (int)($_POST['warehouse_id'] ?? 0),
            'party_id' => (int)($_POST['party_id'] ?? ($_POST['customer_id'] ?? 0)),
            'customer_id' => (int)($_POST['party_id'] ?? ($_POST['customer_id'] ?? 0)),
            'customer_label' => trim((string)($_POST['customer_label'] ?? '')),
            'party_label' => trim((string)($_POST['customer_label'] ?? '')),
            'payment_mode' => 'cash',
            'paid_amount' => 0,
            'due_amount' => 0,
            'cashbox_id' => (int)$pageData['userCashboxId'],
            'received_amount' => (float)($_POST['received_amount'] ?? 0),
            'change_amount' => 0,
            'discount_type' => strtoupper(trim((string)($_POST['discount_type'] ?? 'VALUE'))),
            'discount_value' => (float)($_POST['discount_value'] ?? 0),
            'discount_amount' => 0,
            'grand_total' => 0,
            'print_now' => (int)($_POST['print_now'] ?? 1),
            'notes' => trim((string)($_POST['notes'] ?? '')),
            'collection_note' => trim((string)($_POST['collection_note'] ?? '')),
        ];

        try {
            $result = $this->checkoutService->checkout(
                $pdo,
                $form,
                $pageData['cart'],
                $pageData['cart_lines'],
                (float)$pageData['cart_total'],
                (int)$pageData['userCashboxId'],
                (bool)$pageData['isUserCashboxActive']
            );

            $form = $result['form'];
            $invoiceId = (int)$result['invoice_id'];
            $invoiceNo = (string)$result['invoice_no'];
            $this->cartService->clear();
            $this->forms->clearOld();
            flash_set('success', 'تم ترحيل فاتورة نقطة البيع: ' . $invoiceNo);
            if ((int)$form['print_now'] === 1) {
                $printFormat = (new PrintSettingsService($pdo))->posDefaultPrintFormat();
                $printUrl = url('/prints/sales-invoice?id=' . $invoiceId . '&format=' . $printFormat . '&autoprint=1&close_after_print=1');
                $returnUrl = url('/sales/pos');
                echo '<!doctype html><html lang="ar" dir="rtl"><head><meta charset="utf-8"><title>فتح نافذة الطباعة</title></head><body>';
                echo '<script>';
                echo 'var printUrl=' . json_encode($printUrl) . ';';
                echo 'var returnUrl=' . json_encode($returnUrl) . ';';
                echo 'var popup=window.open(printUrl,"pos_print_popup","width=520,height=720,left=80,top=60,noopener=no,noreferrer=no");';
                echo 'window.location=returnUrl;';
                echo '</script>';
                echo '<p style="font-family:system-ui;padding:24px">تم فتح نافذة طباعة صغيرة... <a href="' . e($returnUrl) . '">متابعة</a></p>';
                echo '</body></html>';
                exit;
            }
            redirect(url('/sales/pos'));
        } catch (Throwable $e) {
            $this->forms->fail('تعذر ترحيل فاتورة نقطة البيع: ' . $e->getMessage(), $form);
        }
    }
}
