<?php
namespace admin\Controllers;

use Domain\Order\OrderAdminService;
use Domain\Product\ProductRepository;
use admin\ViewModels\Common\PaginatedTableViewModel;

class ShopOrderController
{
    private OrderAdminService $service;
    private $productRepo;

    public function __construct(OrderAdminService $service, ProductRepository $productRepo = null)
    {
        $this->service = $service;
        $this->productRepo = $productRepo;
    }

    public function list(): string
    {
        return $this->view_list();
    }

    public function view_list(): string
    {
        $sortableColumns = [
            'number',
            'date_order',
            'status',
            'summary',
            'client',
            'order_email',
            'client_phone',
            'transport',
            'payment_method',
            'total_orders',
            'paid',
        ];

        $statusOptions = ['' => '- status -'];
        foreach ($this->service->statuses() as $statusId => $statusName) {
            $statusOptions[(string)$statusId] = (string)$statusName;
        }

        $filterDefinitions = [
            ['key' => 'number', 'label' => 'Nr zamówienia', 'type' => 'text'],
            ['key' => 'date_from', 'label' => 'Data od', 'type' => 'date'],
            ['key' => 'date_to', 'label' => 'Data do', 'type' => 'date'],
            ['key' => 'status', 'label' => 'Status', 'type' => 'select', 'options' => $statusOptions],
            ['key' => 'client', 'label' => 'Klient', 'type' => 'text'],
            ['key' => 'address', 'label' => 'Adres', 'type' => 'text'],
            ['key' => 'order_email', 'label' => 'Email', 'type' => 'text'],
            ['key' => 'client_phone', 'label' => 'Telefon', 'type' => 'text'],
            ['key' => 'transport', 'label' => 'Dostawa', 'type' => 'text'],
            ['key' => 'payment_method', 'label' => 'Płatność', 'type' => 'text'],
        ];

        $listRequest = \admin\Support\TableListRequestFactory::fromRequest(
            $filterDefinitions,
            $sortableColumns,
            'date_order'
        );

        $result = $this->service->listForAdmin(
            $listRequest['filters'],
            $listRequest['sortColumn'],
            $listRequest['sortDir'],
            $listRequest['page'],
            $listRequest['perPage']
        );

        $statusData = $this->service->statusData();
        $statusesMap = $statusData['names'];
        $statusColorsMap = $statusData['colors'];
        $rows = [];
        $lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;

        foreach ($result['items'] as $item) {
            $orderId = (int)($item['id'] ?? 0);
            $orderNumber = (string)($item['number'] ?? '');
            $statusId = (int)($item['status'] ?? 0);
            $statusLabel = htmlspecialchars((string)($statusesMap[$statusId] ?? ('Status #' . $statusId)), ENT_QUOTES, 'UTF-8');
            $statusColor = isset($statusColorsMap[$statusId]) ? $statusColorsMap[$statusId] : '';

            if ($statusColor !== '') {
                $textColor = $this->contrastTextColor($statusColor);
                $statusHtml = '<span class="label" style="background-color:' . htmlspecialchars($statusColor, ENT_QUOTES, 'UTF-8') . ';color:' . $textColor . '">' . $statusLabel . '</span>';
            } else {
                $statusHtml = $statusLabel;
            }

            $rows[] = [
                'lp' => $lp++ . '.',
                'date_order' => $this->formatDateTime((string)($item['date_order'] ?? '')),
                'number' => '<a href="/admin/shop_order/order_details/order_id=' . $orderId . '">' . htmlspecialchars($orderNumber, ENT_QUOTES, 'UTF-8') . '</a>',
                'paid' => ((int)($item['paid'] ?? 0) === 1)
                    ? '<i class="fa fa-check text-success"></i>'
                    : '<i class="fa fa-times text-dark"></i>',
                'status' => $statusHtml,
                'summary' => number_format((float)($item['summary'] ?? 0), 2, '.', ' ') . ' zł',
                'client' => htmlspecialchars((string)($item['client'] ?? ''), ENT_QUOTES, 'UTF-8') . ' | zamówienia: <strong>' . (int)($item['total_orders'] ?? 0) . '</strong>',
                'address' => (string)($item['address'] ?? ''),
                'order_email' => (string)($item['order_email'] ?? ''),
                'client_phone' => (string)($item['client_phone'] ?? ''),
                'transport' => $this->sanitizeInlineHtml((string)($item['transport'] ?? '')),
                'payment_method' => (string)($item['payment_method'] ?? ''),
                '_actions' => [
                    [
                        'label' => 'Szczegóły',
                        'url' => '/admin/shop_order/order_details/order_id=' . $orderId,
                        'class' => 'btn btn-xs btn-primary',
                    ],
                    [
                        'label' => 'Usuń',
                        'url' => '/admin/shop_order/order_delete/id=' . $orderId,
                        'class' => 'btn btn-xs btn-danger',
                        'confirm' => 'Na pewno chcesz usunąć wybrane zamówienie?',
                        'confirm_ok' => 'Usuń',
                        'confirm_cancel' => 'Anuluj',
                    ],
                ],
            ];
        }

        $total = (int)$result['total'];
        $totalPages = max(1, (int)ceil($total / $listRequest['perPage']));

        $viewModel = new PaginatedTableViewModel(
            [
                ['key' => 'lp', 'label' => 'Lp.', 'class' => 'text-center', 'sortable' => false],
                ['key' => 'date_order', 'sort_key' => 'date_order', 'label' => 'Data dodania', 'class' => 'text-center', 'sortable' => true],
                ['key' => 'number', 'sort_key' => 'number', 'label' => 'Nr zamówienia', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
                ['key' => 'paid', 'sort_key' => 'paid', 'label' => '', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
                ['key' => 'status', 'sort_key' => 'status', 'label' => 'Status', 'sortable' => true, 'raw' => true],
                ['key' => 'summary', 'sort_key' => 'summary', 'label' => 'Wartość', 'class' => 'text-right align-middle', 'sortable' => true],
                ['key' => 'client', 'sort_key' => 'client', 'label' => 'Klient', 'sortable' => true, 'raw' => true],
                ['key' => 'address', 'label' => 'Adres', 'sortable' => false],
                ['key' => 'order_email', 'sort_key' => 'order_email', 'label' => 'Email', 'sortable' => true],
                ['key' => 'client_phone', 'sort_key' => 'client_phone', 'label' => 'Telefon', 'sortable' => true],
                ['key' => 'transport', 'sort_key' => 'transport', 'label' => 'Dostawa', 'sortable' => true, 'raw' => true],
                ['key' => 'payment_method', 'sort_key' => 'payment_method', 'label' => 'Płatność', 'sortable' => true],
            ],
            $rows,
            $listRequest['viewFilters'],
            [
                'column' => $listRequest['sortColumn'],
                'dir' => $listRequest['sortDir'],
            ],
            [
                'page' => $listRequest['page'],
                'per_page' => $listRequest['perPage'],
                'total' => $total,
                'total_pages' => $totalPages,
            ],
            array_merge($listRequest['queryFilters'], [
                'sort' => $listRequest['sortColumn'],
                'dir' => $listRequest['sortDir'],
                'per_page' => $listRequest['perPage'],
            ]),
            $listRequest['perPageOptions'],
            $sortableColumns,
            '/admin/shop_order/list/',
            'Brak danych w tabeli.'
        );

        return \Shared\Tpl\Tpl::view('shop-order/orders-list', [
            'viewModel' => $viewModel,
        ]);
    }

    public function details(): string
    {
        return $this->order_details();
    }

    public function order_details(): string
    {
        $orderId = (int)\Shared\Helpers\Helpers::get('order_id');
        $order = $this->service->details($orderId);

        $coupon = null;
        if (!empty($order) && !empty($order['coupon_id'])) {
            $coupon = ( new \Domain\Coupon\CouponRepository( $GLOBALS['mdb'] ) )->find((int)$order['coupon_id']);
        }

        return \Shared\Tpl\Tpl::view('shop-order/order-details', [
            'order' => $order,
            'coupon' => $coupon,
            'order_statuses' => $this->service->statuses(),
            'next_order_id' => $this->service->nextOrderId($orderId),
            'prev_order_id' => $this->service->prevOrderId($orderId),
        ]);
    }

    public function edit(): string
    {
        return $this->order_edit();
    }

    public function order_edit(): string
    {
        $orderId = (int)\Shared\Helpers\Helpers::get('order_id');
        $transports = ( new \Domain\Transport\TransportRepository( $GLOBALS['mdb'] ) )->allActive();

        // Dane transportów do JS (id, cost, delivery_free)
        $transportsJson = [];
        if (is_array($transports)) {
            foreach ($transports as $t) {
                $transportsJson[] = [
                    'id' => (int)$t['id'],
                    'cost' => (float)$t['cost'],
                    'delivery_free' => (int)($t['delivery_free'] ?? 0),
                ];
            }
        }

        return \Shared\Tpl\Tpl::view('shop-order/order-edit', [
            'order' => $this->service->details($orderId),
            'order_statuses' => $this->service->statuses(),
            'transport' => $transports,
            'payment_methods' => ( new \Domain\PaymentMethod\PaymentMethodRepository( $GLOBALS['mdb'] ) )->allActive(),
            'free_delivery' => $this->service->getFreeDeliveryThreshold(),
            'transports_json' => json_encode($transportsJson),
        ]);
    }

    public function save(): void
    {
        $this->order_save();
    }

    public function order_save(): void
    {
        $orderId = (int)\Shared\Helpers\Helpers::get('order_id');

        // Zapisz produkty PRZED zapisem zamówienia (bo saveOrderByAdmin przelicza summary)
        $productsData = \Shared\Helpers\Helpers::get('products');
        if (is_array($productsData)) {
            $this->service->saveOrderProducts($orderId, $productsData);
        }

        $saved = $this->service->saveOrderByAdmin([
            'order_id' => $orderId,
            'client_name' => (string)\Shared\Helpers\Helpers::get('client_name'),
            'client_surname' => (string)\Shared\Helpers\Helpers::get('client_surname'),
            'client_street' => (string)\Shared\Helpers\Helpers::get('client_street'),
            'client_postal_code' => (string)\Shared\Helpers\Helpers::get('client_postal_code'),
            'client_city' => (string)\Shared\Helpers\Helpers::get('client_city'),
            'client_email' => (string)\Shared\Helpers\Helpers::get('client_email'),
            'firm_name' => (string)\Shared\Helpers\Helpers::get('firm_name'),
            'firm_street' => (string)\Shared\Helpers\Helpers::get('firm_street'),
            'firm_postal_code' => (string)\Shared\Helpers\Helpers::get('firm_postal_code'),
            'firm_city' => (string)\Shared\Helpers\Helpers::get('firm_city'),
            'firm_nip' => (string)\Shared\Helpers\Helpers::get('firm_nip'),
            'transport_id' => (int)\Shared\Helpers\Helpers::get('transport_id'),
            'inpost_paczkomat' => (string)\Shared\Helpers\Helpers::get('inpost_paczkomat'),
            'payment_method_id' => (int)\Shared\Helpers\Helpers::get('payment_method_id'),
        ]);

        if ($saved) {
            \Shared\Helpers\Helpers::alert('Zamówienie zostało zapisane.');
        }

        header('Location: /admin/shop_order/order_details/order_id=' . $orderId);
        exit;
    }

    public function search_products_ajax(): void
    {
        $query = trim((string)\Shared\Helpers\Helpers::get('query'));
        $langId = trim((string)\Shared\Helpers\Helpers::get('lang_id'));
        if ($langId === '') {
            $langId = isset($_SESSION['lang_id']) ? (string)$_SESSION['lang_id'] : 'pl';
        }

        $results = $this->service->searchProducts($query, $langId);

        header('Content-Type: application/json; charset=utf-8');
        echo json_encode(['status' => 'ok', 'products' => $results]);
        exit;
    }

    public function notes_save(): void
    {
        $this->service->saveNotes((int)\Shared\Helpers\Helpers::get('order_id'), (string)\Shared\Helpers\Helpers::get('notes'));
    }

    public function order_status_change(): void
    {
        $response = $this->service->changeStatus(
            (int)\Shared\Helpers\Helpers::get('order_id'),
            (int)\Shared\Helpers\Helpers::get('status'),
            (string)\Shared\Helpers\Helpers::get('email') === 'true'
        );

        echo json_encode($response);
        exit;
    }

    public function order_resend_confirmation_email(): void
    {
        $response = $this->service->resendConfirmationEmail((int)\Shared\Helpers\Helpers::get('order_id'));

        echo json_encode(['result' => $response]);
        exit;
    }

    public function set_order_as_unpaid(): void
    {
        $orderId = (int)\Shared\Helpers\Helpers::get('order_id');
        $this->service->setOrderAsUnpaid($orderId);

        header('Location: /admin/shop_order/order_details/order_id=' . $orderId);
        exit;
    }

    public function set_order_as_paid(): void
    {
        $orderId = (int)\Shared\Helpers\Helpers::get('order_id');
        $this->service->setOrderAsPaid($orderId, (int)\Shared\Helpers\Helpers::get('send_mail') === 1);

        header('Location: /admin/shop_order/order_details/order_id=' . $orderId);
        exit;
    }

    public function send_order_to_apilo(): void
    {
        $orderId = (int)\Shared\Helpers\Helpers::get('order_id');

        if ($this->service->sendOrderToApilo($orderId)) {
            \Shared\Helpers\Helpers::alert('Zamówienie zostanie wysłane ponownie do apilo.com');
        } else {
            \Shared\Helpers\Helpers::alert('Wystąpił błąd podczas wysyłania zamówienia do apilo.com');
        }

        header('Location: /admin/shop_order/order_details/order_id=' . $orderId);
        exit;
    }

    public function toggle_trustmate_send(): void
    {
        echo json_encode($this->service->toggleTrustmateSend((int)\Shared\Helpers\Helpers::get('order_id')));
        exit;
    }

    public function delete(): void
    {
        $this->order_delete();
    }

    public function order_delete(): void
    {
        if ($this->service->deleteOrder((int)\Shared\Helpers\Helpers::get('id'))) {
            \Shared\Helpers\Helpers::alert('Zamówienie zostało usunięte');
        }

        header('Location: /admin/shop_order/list/');
        exit;
    }

    private function formatDateTime(string $value): string
    {
        if ($value === '') {
            return '';
        }

        $ts = strtotime($value);
        if ($ts === false) {
            return $value;
        }

        return date('Y-m-d H:i', $ts);
    }

    private function contrastTextColor(string $hex): string
    {
        $hex = ltrim($hex, '#');
        if (strlen($hex) === 3) {
            $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
        }
        if (strlen($hex) !== 6) {
            return '#fff';
        }
        $r = hexdec(substr($hex, 0, 2));
        $g = hexdec(substr($hex, 2, 2));
        $b = hexdec(substr($hex, 4, 2));
        $luminance = (0.299 * $r + 0.587 * $g + 0.114 * $b) / 255;
        return $luminance > 0.5 ? '#000' : '#fff';
    }

    private function sanitizeInlineHtml(string $html): string
    {
        $html = strip_tags($html, '<b><strong><i><em>');
        return preg_replace('/<(b|strong|i|em)\s[^>]*>/i', '<$1>', $html);
    }
}
