<?php
namespace admin\Controllers;

use Domain\Product\ProductRepository;
use Domain\Category\CategoryRepository;
use Domain\Integrations\IntegrationsRepository;
use Domain\Languages\LanguagesRepository;
use admin\ViewModels\Forms\FormEditViewModel;
use admin\ViewModels\Forms\FormField;
use admin\ViewModels\Forms\FormTab;
use admin\ViewModels\Forms\FormAction;
use admin\ViewModels\Common\PaginatedTableViewModel;
use admin\Support\TableListRequestFactory;

/**
 * Kontroler produktów w panelu administratora.
 * Obsługuje: listę produktów, edycję, zapis, operacje, kombinacje, zdjęcia, pliki, masową edycję.
 */
class ShopProductController
{
    private ProductRepository $repository;
    private IntegrationsRepository $integrationsRepository;
    private LanguagesRepository $languagesRepository;

    public function __construct(ProductRepository $repository, IntegrationsRepository $integrationsRepository, LanguagesRepository $languagesRepository)
    {
        $this->repository = $repository;
        $this->integrationsRepository = $integrationsRepository;
        $this->languagesRepository = $languagesRepository;
    }

    // ─── Krok 6: Lista / widok ───────────────────────────────────────

    /**
     * Lista produktów.
     */
    public function view_list(): string
    {
        $apiloEnabled = $this->integrationsRepository->getSetting( 'apilo', 'enabled' );
        $shopproEnabled = $this->integrationsRepository->getSetting( 'shoppro', 'enabled' );
        $dlang = $this->languagesRepository->defaultLanguage();

        $sortableColumns = [ 'id', 'name', 'price_brutto', 'status', 'promoted', 'quantity' ];

        $filterDefinitions = [
            [
                'key'   => 'search',
                'label' => 'Szukaj (nazwa, EAN, SKU)',
                'type'  => 'text',
            ],
            [
                'key'     => 'status',
                'label'   => 'Aktywny',
                'type'    => 'select',
                'options' => [ '' => '- aktywny -', '1' => 'tak', '0' => 'nie' ],
            ],
            [
                'key'     => 'promoted',
                'label'   => 'Promowany',
                'type'    => 'select',
                'options' => [ '' => '- promowany -', '1' => 'tak', '0' => 'nie' ],
            ],
        ];

        $listRequest = TableListRequestFactory::fromRequest(
            $filterDefinitions,
            $sortableColumns,
            'id'
        );

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

        $rows = [];
        $lp = ( $listRequest['page'] - 1 ) * $listRequest['perPage'] + 1;

        foreach ( $result['items'] as $product ) {
            $id = (int) $product['id'];
            $name = htmlspecialchars( (string) ( $product['languages'][$dlang]['name'] ?? '' ), ENT_QUOTES, 'UTF-8' );
            $imgSrc = !empty( $product['images'][0]['src'] )
                ? $product['images'][0]['src']
                : '/admin/layout/images/no-image.png';
            $imgAlt = htmlspecialchars( (string) ( $product['images'][0]['alt'] ?? '' ), ENT_QUOTES, 'UTF-8' );
            $categories = htmlspecialchars( $this->repository->productCategoriesText( $id ), ENT_QUOTES, 'UTF-8' );
            $sku = htmlspecialchars( (string) ( $product['sku'] ?? '' ), ENT_QUOTES, 'UTF-8' );
            $ean = htmlspecialchars( (string) ( $product['ean'] ?? '' ), ENT_QUOTES, 'UTF-8' );

            $nameHtml = '<div class="product-image"><img src="' . $imgSrc . '" alt="' . $imgAlt . '" class="img-responsive"></div>'
                . '<div class="product-name">'
                . '<a href="/admin/shop_product/product_edit/id=' . $id . '">' . $name . '</a> '
                . '<a href="#" class="text-muted duplicate-product" product-id="' . $id . '">duplikuj</a>'
                . '</div>'
                . '<small class="text-muted product-categories product-categories--cats" title="' . $categories . '">' . $categories . '</small>'
                . '<small class="text-muted product-categories">SKU: ' . $sku . ', EAN: ' . $ean . '</small>';

            $priceHtml = '<input type="text" class="product-price form-control text-right" product-id="' . $id . '" value="' . htmlspecialchars( (string) $product['price_brutto'], ENT_QUOTES, 'UTF-8' ) . '" style="width: 75px;">';
            $promoHtml = '<input type="text" class="product-price-promo form-control text-right" product-id="' . $id . '" value="' . htmlspecialchars( (string) $product['price_brutto_promo'], ENT_QUOTES, 'UTF-8' ) . '" style="width: 75px;">';
            $promotedHtml = $product['promoted'] ? '<span class="text-success text-bold">tak</span>' : 'nie';
            $statusHtml = $product['status'] ? 'tak' : '<span class="text-danger text-bold">nie</span>';
            $quantity = (int) $this->repository->getQuantity( $id );
            $combinationsCount = $this->repository->countCombinations( $id );

            $row = [
                'lp'           => $lp++ . '.',
                'name'         => $nameHtml,
                'price'        => $priceHtml,
                'price_promo'  => $promoHtml,
                'promoted'     => $promotedHtml,
                'status'       => $statusHtml,
                'quantity'     => '<span class="text-muted">' . $quantity . '</span>',
                'combinations' => '<a href="/admin/shop_product/product_combination/product_id=' . $id . '">kombinacje (' . $combinationsCount . ')</a>',
                '_actions'     => [
                    [
                        'label' => 'Edytuj',
                        'url'   => '/admin/shop_product/product_edit/id=' . $id,
                        'class' => 'btn btn-xs btn-primary',
                    ],
                    [
                        'label'   => 'Archiwizuj',
                        'url'     => '/admin/shop_product/product_archive/product_id=' . $id,
                        'class'   => 'btn btn-xs btn-danger',
                        'confirm' => 'Na pewno chcesz przenieść wybrany produkt do archiwum?',
                    ],
                ],
            ];

            if ( $apiloEnabled ) {
                if ( !empty( $product['apilo_product_name'] ) ) {
                    $apiloName = htmlspecialchars( (string) $product['apilo_product_name'], ENT_QUOTES, 'UTF-8' );
                    $apiloShort = htmlspecialchars( mb_substr( (string) $product['apilo_product_name'], 0, 25, 'UTF-8' ), ENT_QUOTES, 'UTF-8' );
                    $row['apilo'] = '<span title="' . $apiloName . '">' . $apiloShort . '...</span><br>'
                        . '<span class="text-danger apilo-delete-linking" product-id="' . $id . '"><i class="fa fa-times"></i>usuń powiązanie</span>';
                } else {
                    $row['apilo'] = '<span class="text-danger apilo-product-search" product-id="' . $id . '">nie przypisano <i class="fa fa-search"></i></span>';
                }
            }


            $rows[] = $row;
        }

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

        $columns = [
            [ 'key' => 'lp', 'label' => '#', 'class' => 'text-center', 'sortable' => false ],
            [ 'key' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true ],
            [ 'key' => 'price', 'sort_key' => 'price_brutto', 'label' => 'Cena', 'class' => 'text-center', 'sortable' => true, 'raw' => true ],
            [ 'key' => 'price_promo', 'label' => 'Cena promocyjna', 'class' => 'text-center', 'sortable' => false, 'raw' => true ],
            [ 'key' => 'promoted', 'sort_key' => 'promoted', 'label' => 'Promowany', 'class' => 'text-center', 'sortable' => true, 'raw' => true ],
            [ 'key' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', 'sortable' => true, 'raw' => true ],
            [ 'key' => 'quantity', 'sort_key' => 'quantity', 'label' => 'Stan MG', 'class' => 'text-center', 'sortable' => true, 'raw' => true ],
        ];

        if ( $apiloEnabled ) {
            $columns[] = [ 'key' => 'apilo', 'label' => 'Apilo', 'class' => 'text-center', 'sortable' => false, 'raw' => true ];
        }

        $columns[] = [ 'key' => 'combinations', 'label' => 'Kombinacje', 'class' => 'text-center', 'sortable' => false, 'raw' => true ];

        $viewModel = new PaginatedTableViewModel(
            $columns,
            $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_product/view_list/',
            'Brak produktów.',
            '/admin/shop_product/product_edit/',
            'Dodaj produkt',
            'shop-product/products-list-custom-script'
        );

        return \Shared\Tpl\Tpl::view( 'shop-product/products-list', [
            'viewModel'       => $viewModel,
            'apilo_enabled'   => $apiloEnabled,
            'shoppro_enabled' => $shopproEnabled,
        ] );
    }

    // ─── Krok 7: Edycja i zapis ─────────────────────────────────────

    /**
     * Formularz edycji produktu.
     */
    public function product_edit(): string
    {
        global $user;

        if ( !$user ) {
            header( 'Location: /admin/' );
            exit;
        }

        $this->repository->deleteNonassignedImages();
        $this->repository->deleteNonassignedFiles();

        $db = $GLOBALS['mdb'];

        $product    = $this->repository->findForAdmin( (int) \Shared\Helpers\Helpers::get( 'id' ) ) ?: [];
        $languages  = $this->languagesRepository->languagesList();
        $categories = ( new CategoryRepository( $db ) )->subcategories( null );
        $layouts    = $this->layoutsForProductEdit( $db );
        $products   = $this->repository->allProductsList();
        $sets       = ( new \Domain\ProductSet\ProductSetRepository( $db ) )->allSets();
        $producers  = ( new \Domain\Producer\ProducerRepository( $db ) )->allProducers();
        $units      = ( new \Domain\Dictionaries\DictionariesRepository( $db ) )->allUnits();
        $dlang      = $this->languagesRepository->defaultLanguage();

        $viewModel = $this->buildProductFormViewModel(
            $product, $languages, $categories, $layouts, $products, $sets, $producers, $units, $dlang
        );

        return \Shared\Tpl\Tpl::view( 'shop-product/product-edit', [
            'form'    => $viewModel,
            'product' => $product,
            'user'    => $user,
        ] );
    }

    private function layoutsForProductEdit($db): array
    {
        if ( class_exists( '\Domain\Layouts\LayoutsRepository' ) ) {
            $rows = ( new \Domain\Layouts\LayoutsRepository( $db ) )->listAll();
            return is_array( $rows ) ? $rows : [];
        }
        return [];
    }

    private function buildProductFormViewModel(
        array $product,
        array $languages,
        array $categories,
        array $layouts,
        array $products,
        array $sets,
        array $producers,
        array $units,
        $dlang
    ): FormEditViewModel {
        $productId = (int) ( $product['id'] ?? 0 );
        $title = $productId > 0
            ? 'Edycja produktu: <u>' . $this->escapeHtml( (string) ( $product['languages'][$dlang]['name'] ?? '' ) ) . '</u>'
            : 'Edycja produktu';

        // Opcje select: copy_from
        $copyFromOptions = [ '' => '---- wersja językowa ----' ];
        foreach ( $languages as $lg ) {
            if ( !empty( $lg['id'] ) ) {
                $copyFromOptions[(string) $lg['id']] = (string) $lg['name'];
            }
        }

        // Opcje select: jednostka miary
        $unitOptions = [ '' => '--- wybierz jednostkę miary ---' ];
        foreach ( $units as $unit ) {
            $unitOptions[(string) $unit['id']] = (string) $unit['text'];
        }

        // Opcje select: layout
        $layoutOptions = [ '' => '---- szablon domyślny ----' ];
        foreach ( $layouts as $layout ) {
            $layoutOptions[(string) $layout['id']] = (string) $layout['name'];
        }

        // Opcje select: producent
        $producerOptions = [ '' => '--- wybierz producenta ---' ];
        foreach ( $producers as $producer ) {
            $producerOptions[(string) $producer['id']] = (string) $producer['name'];
        }

        $tabs = [
            new FormTab( 'description', 'Opis', 'fa-file' ),
            new FormTab( 'tabs', 'Zakładki', 'fa-file' ),
            new FormTab( 'price', 'Cena', 'fa-dollar' ),
            new FormTab( 'stock', 'Magazyn', 'fa-home' ),
            new FormTab( 'settings', 'Ustawienia', 'fa-wrench' ),
            new FormTab( 'seo', 'SEO', 'fa-globe' ),
            new FormTab( 'display', 'Wyświetlanie', 'fa-share-alt' ),
            new FormTab( 'gallery', 'Galeria', 'fa-file-image-o' ),
            new FormTab( 'attachments', 'Załączniki', 'fa-file-archive-o' ),
            new FormTab( 'related', 'Produkty powiązane', 'fa-exchange' ),
            new FormTab( 'xml', 'XML', 'fa-file-excel-o' ),
            new FormTab( 'custom_fields', 'Dodatkowe pola', 'fa-file-o' ),
            new FormTab( 'gpsr', 'GPSR', 'fa-file-o' ),
        ];

        $fields = [
            FormField::hidden( 'id', $productId ),

            // Tab: Opis — sekcja językowa
            FormField::langSection( 'product_description', 'description', [
                FormField::select( 'copy_from', [
                    'label'   => 'Wyświetlaj treść z wersji',
                    'options' => $copyFromOptions,
                ] ),
                FormField::text( 'name', [
                    'label'      => 'Nazwa',
                    'attributes' => [ 'id' => 'name' ],
                ] ),
                FormField::text( 'warehouse_message_zero', [
                    'label'      => 'Komunikat gdy stan magazynowy równy 0',
                    'attributes' => [ 'id' => 'warehouse_message_zero' ],
                ] ),
                FormField::text( 'warehouse_message_nonzero', [
                    'label'      => 'Komunikat gdy stan magazynowy większy niż 0',
                    'attributes' => [ 'id' => 'warehouse_message_nonzero' ],
                ] ),
                FormField::editor( 'short_description', [
                    'label'      => 'Krótki opis',
                    'toolbar'    => 'MyToolbar',
                    'height'     => 250,
                    'attributes' => [ 'id' => 'short_description' ],
                ] ),
                FormField::editor( 'description', [
                    'label'      => 'Opis',
                    'toolbar'    => 'MyToolbar',
                    'height'     => 250,
                    'attributes' => [ 'id' => 'description' ],
                ] ),
            ] ),

            // Tab: Zakładki — sekcja językowa
            FormField::langSection( 'product_tabs', 'tabs', [
                FormField::text( 'tab_name_1', [
                    'label'      => 'Nazwa zakładki (1)',
                    'attributes' => [ 'id' => 'tab_name_1' ],
                ] ),
                FormField::editor( 'tab_description_1', [
                    'label'      => 'Zawartość zakładki (1)',
                    'toolbar'    => 'MyToolbar',
                    'height'     => 250,
                    'attributes' => [ 'id' => 'tab_description_1' ],
                ] ),
                FormField::text( 'tab_name_2', [
                    'label'      => 'Nazwa zakładki (2)',
                    'attributes' => [ 'id' => 'tab_name_2' ],
                ] ),
                FormField::editor( 'tab_description_2', [
                    'label'      => 'Zawartość zakładki (2)',
                    'toolbar'    => 'MyToolbar',
                    'height'     => 250,
                    'attributes' => [ 'id' => 'tab_description_2' ],
                ] ),
            ] ),

            // Tab: Cena
            FormField::text( 'vat', [
                'label'      => 'VAT (%)',
                'tab'        => 'price',
                'value'      => $productId ? $product['vat'] : 23,
                'attributes' => [ 'id' => 'vat', 'class' => 'int-format' ],
            ] ),
            FormField::text( 'price_netto', [
                'label'      => 'Cena netto (PLN)',
                'tab'        => 'price',
                'value'      => $product['price_netto'] ?? '',
                'attributes' => [ 'id' => 'price_netto', 'class' => 'number-format' ],
            ] ),
            FormField::text( 'price_brutto', [
                'label'      => 'Cena brutto (PLN)',
                'tab'        => 'price',
                'value'      => $product['price_brutto'] ?? '',
                'attributes' => [ 'id' => 'price_brutto', 'class' => 'number-format' ],
            ] ),
            FormField::text( 'price_netto_promo', [
                'label'      => 'Promocyjna cena netto (PLN)',
                'tab'        => 'price',
                'value'      => $product['price_netto_promo'] ?? '',
                'attributes' => [ 'id' => 'price_netto_promo', 'class' => 'number-format' ],
            ] ),
            FormField::text( 'price_brutto_promo', [
                'label'      => 'Promocyjna cena brutto (PLN)',
                'tab'        => 'price',
                'value'      => $product['price_brutto_promo'] ?? '',
                'attributes' => [ 'id' => 'price_brutto_promo', 'class' => 'number-format' ],
            ] ),
            FormField::select( 'product_unit', [
                'label'   => 'Jednostka miary',
                'tab'     => 'price',
                'options' => $unitOptions,
                'value'   => $product['product_unit_id'] ?? '',
            ] ),
            FormField::text( 'weight', [
                'label'      => 'Waga/pojemność',
                'tab'        => 'price',
                'value'      => $product['weight'] ?? '',
                'attributes' => [ 'id' => 'weight', 'class' => 'number-format' ],
            ] ),

            // Tab: Magazyn
            FormField::text( 'quantity', [
                'label'      => 'Stan magazynowy',
                'tab'        => 'stock',
                'value'      => $product['quantity'] ?? '',
                'attributes' => [ 'id' => 'quantity', 'class' => 'int-format' ],
            ] ),
            FormField::switch( 'stock_0_buy', [
                'label' => 'Pozwól zamawiać gdy stan 0',
                'tab'   => 'stock',
                'value' => (int) ( $product['stock_0_buy'] ?? 0 ) === 1,
            ] ),
            FormField::text( 'wp', [
                'label'      => 'Współczynnik WP',
                'tab'        => 'stock',
                'value'      => $product['wp'] ?? '',
                'attributes' => [ 'id' => 'wp', 'class' => 'number-format' ],
            ] ),
            FormField::custom( 'sku_field', $this->renderSkuField( $product ), [ 'tab' => 'stock' ] ),
            FormField::text( 'ean', [
                'label'      => 'EAN',
                'tab'        => 'stock',
                'value'      => $product['ean'] ?? '',
                'attributes' => [ 'id' => 'ean' ],
            ] ),

            // Tab: Ustawienia
            FormField::switch( 'status', [
                'label' => 'Widoczny',
                'tab'   => 'settings',
                'value' => ( (int) ( $product['status'] ?? 0 ) === 1 ) || $productId === 0,
            ] ),
            FormField::switch( 'promoted', [
                'label' => 'Promowany',
                'tab'   => 'settings',
                'value' => (int) ( $product['promoted'] ?? 0 ) === 1,
            ] ),
            FormField::date( 'new_to_date', [
                'label' => 'Nowość do dnia',
                'tab'   => 'settings',
                'value' => $product['new_to_date'] ?? '',
            ] ),
            FormField::switch( 'additional_message', [
                'label' => 'Wyświetlaj pole na dodatkową wiadomość',
                'tab'   => 'settings',
                'value' => (int) ( $product['additional_message'] ?? 0 ) === 1,
            ] ),
            FormField::switch( 'additional_message_required', [
                'label' => 'Dodatkowa wiadomość jest wymagana',
                'tab'   => 'settings',
                'value' => (int) ( $product['additional_message_required'] ?? 0 ) === 1,
            ] ),
            FormField::text( 'additional_message_text', [
                'label'      => 'Dodatkowa wiadomość (treść komunikatu)',
                'tab'        => 'settings',
                'value'      => $product['additional_message_text'] ?? '',
                'attributes' => [ 'id' => 'additional_message_text' ],
            ] ),

            // Tab: SEO — sekcja językowa
            FormField::langSection( 'product_seo', 'seo', [
                FormField::text( 'seo_link', [
                    'label'      => 'Link SEO',
                    'attributes' => [
                        'id'           => 'seo_link',
                        'icon_content' => 'generuj',
                        'icon_js'      => 'generate_seo_links( "{lang}", $( "#name_{lang}" ).val(), ' . $productId . ' );',
                    ],
                ] ),
                FormField::text( 'meta_title', [
                    'label'      => 'Meta title',
                    'attributes' => [ 'id' => 'meta_title' ],
                ] ),
                FormField::textarea( 'meta_description', [
                    'label'      => 'Meta description',
                    'attributes' => [ 'id' => 'meta_description' ],
                ] ),
                FormField::textarea( 'meta_keywords', [
                    'label'      => 'Meta keywords',
                    'attributes' => [ 'id' => 'meta_keywords' ],
                ] ),
                FormField::text( 'canonical', [
                    'label'      => 'Canonical',
                    'attributes' => [ 'id' => 'canonical' ],
                ] ),
            ] ),

            // Tab: Wyświetlanie
            FormField::select( 'layout_id', [
                'label'   => 'Szablon',
                'tab'     => 'display',
                'options' => $layoutOptions,
                'value'   => $product['layout_id'] ?? '',
            ] ),
            FormField::custom( 'categories_tree', $this->renderCategoriesTree( $categories, $product, $dlang ), [ 'tab' => 'display' ] ),

            // Tab: Galeria
            FormField::custom( 'gallery_box', $this->renderGalleryBox( $product ), [ 'tab' => 'gallery' ] ),

            // Tab: Załączniki
            FormField::custom( 'files_box', $this->renderFilesBox( $product ), [ 'tab' => 'attachments' ] ),

            // Tab: Produkty powiązane
            FormField::custom( 'related_products', $this->renderRelatedProducts( $product, $products, $sets ), [ 'tab' => 'related' ] ),

            // Tab: XML
            FormField::text( 'custom_label_0', [ 'label' => 'Custom label 0', 'tab' => 'xml', 'value' => $product['custom_label_0'] ?? '' ] ),
            FormField::text( 'custom_label_1', [ 'label' => 'Custom label 1', 'tab' => 'xml', 'value' => $product['custom_label_1'] ?? '' ] ),
            FormField::text( 'custom_label_2', [ 'label' => 'Custom label 2', 'tab' => 'xml', 'value' => $product['custom_label_2'] ?? '' ] ),
            FormField::text( 'custom_label_3', [ 'label' => 'Custom label 3', 'tab' => 'xml', 'value' => $product['custom_label_3'] ?? '' ] ),
            FormField::text( 'custom_label_4', [ 'label' => 'Custom label 4', 'tab' => 'xml', 'value' => $product['custom_label_4'] ?? '' ] ),

            // Tab: Dodatkowe pola
            FormField::custom( 'custom_fields_box', $this->renderCustomFieldsBox( $product ), [ 'tab' => 'custom_fields' ] ),

            // Tab: GPSR
            FormField::select( 'producer_id', [
                'label'   => 'Producent',
                'tab'     => 'gpsr',
                'options' => $producerOptions,
                'value'   => $product['producer_id'] ?? '',
            ] ),
            FormField::langSection( 'product_gpsr', 'gpsr', [
                FormField::editor( 'security_information', [
                    'label'      => 'Informacje o bezpieczeństwie',
                    'toolbar'    => 'MyToolbar',
                    'height'     => 250,
                    'attributes' => [ 'id' => 'security_information' ],
                ] ),
            ] ),
        ];

        $saveUrl = '/admin/shop_product/save/' . ( $productId > 0 ? 'id=' . $productId : '' );
        $backUrl = '/admin/shop_product/view_list/';

        $actions = [
            FormAction::save( $saveUrl, $backUrl ),
            FormAction::cancel( $backUrl ),
        ];

        if ( $productId > 0 ) {
            $previewUrl = $this->repository->getProductUrl( $productId );
            $actions[] = FormAction::preview( $previewUrl );
        }

        return new FormEditViewModel(
            'product-edit',
            $title,
            $product,
            $fields,
            $tabs,
            $actions,
            'POST',
            $saveUrl,
            $backUrl,
            true,
            [ 'id' => $productId ],
            $languages
        );
    }

    private function renderSkuField( array $product ): string
    {
        $productId = (int) ( $product['id'] ?? 0 );
        $sku = $this->escapeHtml( (string) ( $product['sku'] ?? '' ) );

        return \Shared\Html\Html::input_icon( [
            'label'        => 'Kod SKU',
            'name'         => 'sku',
            'id'           => 'sku',
            'value'        => $sku,
            'icon_content' => 'generuj',
            'icon_js'      => 'generate_sku_code( ' . $productId . ' );',
        ] );
    }

    private function renderCategoriesTree( array $categories, array $product, $dlang ): string
    {
        $html = '<div class="form-group row">';
        $html .= '<label class="col-md-4 control-label">Wyświetlaj w:</label>';
        $html .= '<div class="col-md-8">';
        $html .= '<div class="menu_sortable">';
        $html .= '<ol class="sortable" id="sortable">';

        foreach ( $categories as $category ) {
            $catId = (int) $category['id'];
            $catTitle = $this->escapeHtml( (string) ( $category['languages'][$dlang]['title'] ?? '' ) );
            $checked = is_array( $product['categories'] ?? null ) && in_array( $catId, $product['categories'] );

            $html .= '<li id="list_' . $catId . '" class="category_' . $catId . '" category="' . $catId . '">';
            $html .= '<div class="context_0 content content_menu">';
            $html .= '<button type="button" class="disclose layout-tree-toggle" aria-expanded="false" title="Rozwiń / zwiń"><i class="fa fa-caret-right"></i></button>';
            if ( empty( $category['status'] ) ) {
                $html .= '<i class="fa fa-ban fa-lg text-danger" title="Kategoria nieaktywna"></i>';
            }
            $html .= '<input type="checkbox" class="g-checkbox" name="categories[]" value="' . $catId . '"' . ( $checked ? ' checked="checked"' : '' ) . ' />';
            $html .= '<b>' . $catTitle . '</b>';
            $html .= '</div>';
            $html .= \Shared\Tpl\Tpl::view( 'shop-product/subcategories-list', [
                'categories'         => ( new CategoryRepository( $GLOBALS['mdb'] ) )->subcategories( $catId ),
                'product_categories' => $product['categories'] ?? [],
                'dlang'              => $dlang,
                'name'               => null,
            ] );
            $html .= '</li>';
        }

        $html .= '</ol></div></div><div class="clear"></div></div>';

        return $html;
    }

    private function renderGalleryBox( array $product ): string
    {
        $html = '<ul id="images-list">';
        $images = is_array( $product['images'] ?? null ) ? $product['images'] : [];
        foreach ( $images as $img ) {
            $id  = (int) ( $img['id'] ?? 0 );
            $src = $this->escapeHtml( (string) ( $img['src'] ?? '' ) );
            $alt = $this->escapeHtml( (string) ( $img['alt'] ?? '' ) );

            $html .= '<li id="image-' . $id . '">';
            $html .= '<img class="article-image lozad" data-src="/libraries/thumb.php?img=' . $src . '&w=300&h=300">';
            $html .= '<a href="#" class="input-group-addon btn btn-danger article_image_delete" image-id="' . $id . '"><i class="fa fa-trash"></i></a>';
            $html .= '<input type="text" class="form-control image-alt" value="' . $alt . '" image-id="' . $id . '" placeholder="atrybut alt...">';
            $html .= '</li>';
        }
        $html .= '</ul>';
        $html .= '<div id="images-uploader">Twoja przeglądarka nie obsługuje uploadu plików.</div>';

        return $html;
    }

    private function renderFilesBox( array $product ): string
    {
        $html = '<ul id="files-list">';
        $files = is_array( $product['files'] ?? null ) ? $product['files'] : [];
        foreach ( $files as $file ) {
            $id  = (int) ( $file['id'] ?? 0 );
            $src = (string) ( $file['src'] ?? '' );
            $name = trim( (string) ( $file['name'] ?? '' ) );
            if ( $name === '' ) {
                $parts = explode( '/', $src );
                $name = (string) end( $parts );
            }
            $name = $this->escapeHtml( $name );

            $html .= '<li id="file-' . $id . '"><div class="input-group">';
            $html .= '<input type="text" class="product_file_edit form-control" file_id="' . $id . '" value="' . $name . '" />';
            $html .= '<a href="#" class="input-group-addon btn btn-info product_file_delete" file_id="' . $id . '"><i class="fa fa-trash"></i></a>';
            $html .= '</div></li>';
        }
        $html .= '</ul>';
        $html .= '<div id="files-uploader">Twoja przeglądarka nie obsługuje uploadu plików.</div>';

        return $html;
    }

    private function renderRelatedProducts( array $product, array $products, array $sets ): string
    {
        $productId = (int) ( $product['id'] ?? 0 );

        $html = '<div class="form-group row">';
        $html .= '<label class="col-lg-4 control-label">Wybierz zdefiniowany komplet produktów:</label>';
        $html .= '<div class="col-lg-8">';
        $html .= '<select id="set" class="form-control" name="set">';
        $html .= '<option value="">wybierz komplet...</option>';
        foreach ( $sets as $set ) {
            $selected = ( ( $product['set_id'] ?? '' ) == $set['id'] ) ? ' selected="selected"' : '';
            $html .= '<option value="' . (int) $set['id'] . '"' . $selected . '>' . $this->escapeHtml( $set['name'] ) . '</option>';
        }
        $html .= '</select></div></div>';

        $html .= '<div class="form-group row">';
        $html .= '<label class="col-lg-4 control-label">Produkty powiązane:</label>';
        $html .= '<div class="col-lg-8">';
        $html .= '<select id="products_related" multiple name="products_related[]" placeholder="produkty powiązane">';
        $html .= '<option value="">wybierz produkt...</option>';
        foreach ( $products as $key => $val ) {
            if ( (int) $key !== $productId ) {
                $selected = ( is_array( $product['products_related'] ?? null ) && in_array( $key, $product['products_related'] ) ) ? ' selected' : '';
                $html .= '<option value="' . (int) $key . '"' . $selected . '>' . $this->escapeHtml( (string) $val ) . '</option>';
            }
        }
        $html .= '</select></div></div>';

        return $html;
    }

    private function renderCustomFieldsBox( array $product ): string
    {
        $html = '<a href="#" class="btn btn-success" id="add_custom_field"><i class="fa fa-plus"></i> dodaj niestandardowe pole</a>';
        $html .= '<div class="additional_fields pt-3">';

        $customFields = is_array( $product['custom_fields'] ?? null ) ? $product['custom_fields'] : [];
        foreach ( $customFields as $field ) {
            $isRequired = !empty( $field['is_required'] );
            $fieldName = $this->escapeHtml( (string) ( $field['name'] ?? '' ) );
            $fieldType = (string) ( $field['type'] ?? 'text' );

            $html .= '<div class="form-group row custom-field-row bg-white p-4">';
            $html .= '<div class="form-group row"><label class="col-sm-3 control-label">Nazwa pola:</label>';
            $html .= '<div class="col-sm-9"><input type="text" class="form-control" name="custom_field_name[]" value="' . $fieldName . '"></div></div>';
            $html .= '<div class="form-group row"><label class="col-sm-3 control-label">Rodzaj pola:</label>';
            $html .= '<div class="col-sm-9"><select class="form-control" name="custom_field_type[]">';
            $html .= '<option value="text"' . ( $fieldType === 'text' ? ' selected' : '' ) . '>Tekst</option>';
            $html .= '<option value="image"' . ( $fieldType === 'image' ? ' selected' : '' ) . '>Obrazek</option>';
            $html .= '</select></div></div>';
            $html .= '<div class="form-group row"><label class="col-sm-3 control-label">Status pola:</label>';
            $html .= '<div class="col-sm-9"><label style="margin:0; font-weight:normal;" class="d-flex align-items-center mt-3">';
            $html .= '<input type="checkbox" class="custom-field-required mt-0 mr-3" name="custom_field_required[]"' . ( $isRequired ? ' checked' : '' ) . '> wymagane';
            $html .= '</label></div></div>';
            $html .= '<div class="form-group row"><div class="col-sm-12 text-right">';
            $html .= '<span class="input-group-addon btn btn-info" onclick="remove_custom_filed( $( this ) );">usuń</span>';
            $html .= '</div></div></div>';
        }

        $html .= '</div>';

        return $html;
    }

    private function escapeHtml( string $value ): string
    {
        return htmlspecialchars( $value, ENT_QUOTES, 'UTF-8' );
    }

    private function resolveSavePayload(): array
    {
        $legacyRaw = \Shared\Helpers\Helpers::get( 'values' );
        if ( $legacyRaw !== null && $legacyRaw !== '' ) {
            $legacy = json_decode( (string) $legacyRaw, true );
            if ( is_array( $legacy ) ) {
                return $legacy;
            }
        }

        $payload = $_POST;
        unset( $payload['_form_id'] );

        return is_array( $payload ) ? $payload : [];
    }

    /**
     * AJAX: zapis produktu.
     */
    public function save(): void
    {
        $response = [ 'success' => false, 'status' => 'error', 'msg' => 'Podczas zapisywania produktu wystąpił błąd. Proszę spróbować ponownie.' ];
        $values = $this->resolveSavePayload();

        if ( $values ) {
            $id = $this->repository->saveProduct( $values );
            if ( $id ) {
                $response = [ 'success' => true, 'status' => 'ok', 'message' => 'Produkt został zapisany.', 'msg' => 'Produkt został zapisany.', 'id' => $id ];
            }
        }

        echo json_encode( $response );
        exit;
    }

    // ─── Krok 8: Operacje na produktach ──────────────────────────────

    /**
     * Duplikowanie produktu.
     */
    public function duplicate_product(): void
    {
        if ( $this->repository->duplicate( (int) \Shared\Helpers\Helpers::get( 'product-id' ), (bool) (int) \Shared\Helpers\Helpers::get( 'combination' ) ) ) {
            \Shared\Helpers\Helpers::set_message( 'Produkt został zduplikowany.' );
        } else {
            \Shared\Helpers\Helpers::alert( 'Podczas duplikowania produktu wystąpił błąd. Proszę spróbować ponownie' );
        }

        header( 'Location: /admin/shop_product/view_list/' );
        exit;
    }

    /**
     * Archiwizacja produktu.
     */
    public function product_archive(): void
    {
        if ( $this->repository->archive( (int) \Shared\Helpers\Helpers::get( 'product_id' ) ) ) {
            \Shared\Helpers\Helpers::alert( 'Produkt został przeniesiony do archiwum.' );
        } else {
            \Shared\Helpers\Helpers::alert( 'Podczas przenoszenia produktu do archiwum wystąpił błąd. Proszę spróbować ponownie' );
        }

        header( 'Location: /admin/shop_product/view_list/' );
        exit;
    }

    /**
     * Przywrócenie z archiwum.
     */
    public function product_unarchive(): void
    {
        if ( $this->repository->unarchive( (int) \Shared\Helpers\Helpers::get( 'product_id' ) ) ) {
            \Shared\Helpers\Helpers::alert( 'Produkt został przywrócony z archiwum.' );
        } else {
            \Shared\Helpers\Helpers::alert( 'Podczas przywracania produktu z archiwum wystąpił błąd. Proszę spróbować ponownie' );
        }

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

    /**
     * Usunięcie produktu.
     */
    public function product_delete(): void
    {
        if ( $this->repository->delete( (int) \Shared\Helpers\Helpers::get( 'id' ) ) ) {
            \Shared\Helpers\Helpers::set_message( 'Produkt został usunięty.' );
        } else {
            \Shared\Helpers\Helpers::alert( 'Podczas usuwania produktu wystąpił błąd. Proszę spróbować ponownie' );
        }

        header( 'Location: /admin/shop_product/view_list/' );
        exit;
    }

    /**
     * Zmiana statusu produktu (aktywny/nieaktywny).
     */
    public function change_product_status(): void
    {
        if ( $this->repository->toggleStatus( (int) \Shared\Helpers\Helpers::get( 'product-id' ) ) ) {
            \Shared\Helpers\Helpers::set_message( 'Status produktu został zmieniony' );
        }

        header( 'Location: ' . $_SERVER['HTTP_REFERER'] );
        exit;
    }

    /**
     * AJAX: szybka zmiana ceny brutto.
     */
    public function product_change_price_brutto(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas zmiany ceny wystąpił błąd. Proszę spróbować ponownie.' ];

        if ( $this->repository->updatePriceBrutto( (int) \Shared\Helpers\Helpers::get( 'product_id' ), \Shared\Helpers\Helpers::get( 'price' ) ) ) {
            $response = [ 'status' => 'ok' ];
        }

        echo json_encode( $response );
        exit;
    }

    /**
     * AJAX: szybka zmiana ceny promocyjnej brutto.
     */
    public function product_change_price_brutto_promo(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas zmiany ceny wystąpił błąd. Proszę spróbować ponownie.' ];

        if ( $this->repository->updatePriceBruttoPromo( (int) \Shared\Helpers\Helpers::get( 'product_id' ), \Shared\Helpers\Helpers::get( 'price' ) ) ) {
            $response = [ 'status' => 'ok' ];
        }

        echo json_encode( $response );
        exit;
    }

    /**
     * AJAX: szybka zmiana custom label (Google XML).
     */
    public function product_change_custom_label(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas zmiany google xml label wystąpił błąd. Proszę spróbować ponownie.' ];

        if ( $this->repository->updateCustomLabel( (int) \Shared\Helpers\Helpers::get( 'product_id' ), \Shared\Helpers\Helpers::get( 'custom_label' ), \Shared\Helpers\Helpers::get( 'value' ) ) ) {
            $response = [ 'status' => 'ok' ];
        }

        echo json_encode( $response );
        exit;
    }

    /**
     * AJAX: sugestie custom label.
     */
    public function product_custom_label_suggestions(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas pobierania sugestii dla custom label wystąpił błąd. Proszę spróbować ponownie.' ];

        $suggestions = $this->repository->customLabelSuggestions( \Shared\Helpers\Helpers::get( 'custom_label' ), \Shared\Helpers\Helpers::get( 'label_type' ) );
        if ( $suggestions ) {
            $response = [ 'status' => 'ok', 'suggestions' => $suggestions ];
        }

        echo json_encode( $response );
        exit;
    }

    /**
     * AJAX: zapis custom label produktu.
     */
    public function product_custom_label_save(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania custom label wystąpił błąd. Proszę spróbować ponownie.' ];

        if ( $this->repository->saveCustomLabel( (int) \Shared\Helpers\Helpers::get( 'product_id' ), \Shared\Helpers\Helpers::get( 'custom_label' ), \Shared\Helpers\Helpers::get( 'label_type' ) ) ) {
            $response = [ 'status' => 'ok' ];
        }

        echo json_encode( $response );
        exit;
    }

    /**
     * AJAX: pobierz bezpośredni URL produktu na frontendzie.
     */
    public function ajax_product_url(): void
    {
        echo json_encode( [ 'url' => $this->repository->getProductUrl( (int) \Shared\Helpers\Helpers::get( 'product_id' ) ) ] );
        exit;
    }

    /**
     * AJAX: generowanie kodu SKU.
     */
    public function generate_sku_code(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas generowania kodu sku wystąpił błąd. Proszę spróbować ponownie.' ];

        $sku = $this->repository->generateSkuCode();
        if ( $sku ) {
            $response = [ 'status' => 'ok', 'sku' => $sku ];
        }

        echo json_encode( $response );
        exit;
    }

    // ─── Krok 9: Kombinacje ─────────────────────────────────────────

    /**
     * Widok kombinacji produktu.
     */
    public function product_combination(): string
    {
        $db = $GLOBALS['mdb'];

        return \Shared\Tpl\Tpl::view( 'shop-product/product-combination', [
            'product'              => $this->repository->findForAdmin( (int) \Shared\Helpers\Helpers::get( 'product_id' ) ),
            'attributes'           => ( new \Domain\Attribute\AttributeRepository( $db ) )->getAttributesListForCombinations(),
            'default_language'     => $this->languagesRepository->defaultLanguage(),
            'product_permutations' => $this->repository->getCombinationsForTable( (int) \Shared\Helpers\Helpers::get( 'product_id' ) ),
        ] );
    }

    /**
     * Generowanie kombinacji.
     */
    public function generate_combination(): void
    {
        $attributes = [];
        foreach ( $_POST as $key => $val ) {
            if ( strpos( $key, 'attribute_' ) !== false ) {
                $attribute = explode( 'attribute_', $key );
                $attributes[ $attribute[1] ] = $val;
            }
        }

        if ( $this->repository->generateCombinations( (int) \Shared\Helpers\Helpers::get( 'product_id' ), $attributes ) ) {
            \Shared\Helpers\Helpers::alert( 'Kombinacje produktu zostały wygenerowane.' );
        }

        header( 'Location: /admin/shop_product/product_combination/product_id=' . (int) \Shared\Helpers\Helpers::get( 'product_id' ) );
        exit;
    }

    /**
     * Usunięcie kombinacji.
     */
    public function delete_combination(): void
    {
        if ( $this->repository->deleteCombination( (int) \Shared\Helpers\Helpers::get( 'combination_id' ) ) ) {
            \Shared\Helpers\Helpers::alert( 'Kombinacja produktu została usunięta' );
        } else {
            \Shared\Helpers\Helpers::alert( 'Podczas usuwania kombinacji produktu wystąpił błąd. Proszę spróbować ponownie' );
        }

        header( 'Location: /admin/shop_product/product_combination/product_id=' . \Shared\Helpers\Helpers::get( 'product_id' ) );
        exit;
    }

    /**
     * AJAX: zapis stock_0_buy kombinacji.
     */
    public function product_combination_stock_0_buy_save(): void
    {
        $this->repository->saveCombinationStock0Buy( (int) \Shared\Helpers\Helpers::get( 'product_id' ), \Shared\Helpers\Helpers::get( 'stock_0_buy' ) );
        echo json_encode( [ 'status' => 'ok' ] );
        exit;
    }

    /**
     * AJAX: zapis SKU kombinacji.
     */
    public function product_combination_sku_save(): void
    {
        $this->repository->saveCombinationSku( (int) \Shared\Helpers\Helpers::get( 'product_id' ), \Shared\Helpers\Helpers::get( 'sku' ) );
        echo json_encode( [ 'status' => 'ok' ] );
        exit;
    }

    /**
     * AJAX: zapis ilości kombinacji.
     */
    public function product_combination_quantity_save(): void
    {
        $this->repository->saveCombinationQuantity( (int) \Shared\Helpers\Helpers::get( 'product_id' ), \Shared\Helpers\Helpers::get( 'quantity' ) );
        echo json_encode( [ 'status' => 'ok' ] );
        exit;
    }

    /**
     * AJAX: zapis ceny kombinacji.
     */
    public function product_combination_price_save(): void
    {
        $this->repository->saveCombinationPrice( (int) \Shared\Helpers\Helpers::get( 'product_id' ), \Shared\Helpers\Helpers::get( 'price' ) );
        echo json_encode( [ 'status' => 'ok' ] );
        exit;
    }

    /**
     * AJAX: usunięcie kombinacji bez przeładowania strony.
     */
    public function delete_combination_ajax(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas usuwania kombinacji wystąpił błąd.' ];

        if ( $this->repository->deleteCombination( (int) \Shared\Helpers\Helpers::get( 'combination_id' ) ) ) {
            $response = [ 'status' => 'ok' ];
        }

        echo json_encode( $response );
        exit;
    }

    // ─── Krok 10: Zdjęcia i pliki ───────────────────────────────────

    /**
     * AJAX: usunięcie zdjęcia produktu.
     */
    public function image_delete(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas usuwania zdjecia wystąpił błąd. Proszę spróbować ponownie.' ];

        if ( $this->repository->deleteImage( (int) \Shared\Helpers\Helpers::get( 'image_id' ) ) ) {
            $response = [ 'status' => 'ok' ];
        }

        echo json_encode( $response );
        exit;
    }

    /**
     * AJAX: zapis kolejności zdjęć.
     */
    public function images_order_save(): void
    {
        if ( $this->repository->saveImagesOrder( (int) \Shared\Helpers\Helpers::get( 'product_id' ), \Shared\Helpers\Helpers::get( 'order' ) ) ) {
            echo json_encode( [ 'status' => 'ok', 'msg' => 'Produkt został zapisany.' ] );
        }

        exit;
    }

    /**
     * AJAX: zmiana alt zdjęcia.
     */
    public function image_alt_change(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas zmiany atrybutu alt zdjęcia wystąpił błąd. Proszę spróbować ponownie.' ];

        if ( $this->repository->updateImageAlt( (int) \Shared\Helpers\Helpers::get( 'image_id' ), \Shared\Helpers\Helpers::get( 'image_alt' ) ) ) {
            $response = [ 'status' => 'ok' ];
        }

        echo json_encode( $response );
        exit;
    }

    /**
     * AJAX: usunięcie pliku produktu (migracja z ajax/shop.php).
     */
    public function product_file_delete(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas usuwania pliku wystąpił błąd.' ];

        if ( $this->repository->deleteFile( (int) \Shared\Helpers\Helpers::get( 'file_id' ) ) ) {
            $response = [ 'status' => 'ok' ];
        }

        echo json_encode( $response );
        exit;
    }

    /**
     * AJAX: zmiana nazwy pliku (migracja z ajax/shop.php).
     */
    public function product_file_name_change(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas zmiany nazwy pliku wystąpił błąd.' ];

        if ( $this->repository->updateFileName( (int) \Shared\Helpers\Helpers::get( 'file_id' ), \Shared\Helpers\Helpers::get( 'file_name' ) ) ) {
            $response = [ 'status' => 'ok' ];
        }

        echo json_encode( $response );
        exit;
    }

    /**
     * AJAX: usunięcie zdjęcia produktu (migracja z ajax/shop.php).
     */
    public function product_image_delete(): void
    {
        $response = [ 'status' => 'error', 'msg' => 'Podczas usuwania zdjęcia wystąpił błąd.' ];

        if ( $this->repository->deleteImage( (int) \Shared\Helpers\Helpers::get( 'image_id' ) ) ) {
            $response = [ 'status' => 'ok' ];
        }

        echo json_encode( $response );
        exit;
    }

    // ─── Masowa edycja (istniejące) ──────────────────────────────────

    /**
     * Widok masowej edycji produktów.
     */
    public function mass_edit(): string
    {
        $categoryRepository = new CategoryRepository( $GLOBALS['mdb'] );

        return \Shared\Tpl\Tpl::view( 'shop-product/mass-edit', [
            'products'   => $this->repository->allProductsForMassEdit(),
            'categories' => $categoryRepository->subcategories( null ),
            'dlang'      => $this->languagesRepository->defaultLanguage(),
        ] );
    }

    /**
     * AJAX: zastosowanie rabatu procentowego na zaznaczonych produktach.
     */
    public function mass_edit_save(): void
    {
        $discountPercent = \Shared\Helpers\Helpers::get( 'discount_percent' );
        $products = \Shared\Helpers\Helpers::get( 'products' );

        if ( $discountPercent != '' && $products && is_array( $products ) && count( $products ) > 0 ) {
            $productId = (int) $products[0];
            $result = $this->repository->applyDiscountPercent( $productId, (float) $discountPercent );

            if ( $result !== null ) {
                echo json_encode( [
                    'status'             => 'ok',
                    'price_brutto_promo' => $result['price_brutto_promo'],
                    'price_brutto'       => $result['price_brutto'],
                ] );
                exit;
            }
        }

        echo json_encode( [ 'status' => 'error' ] );
        exit;
    }

    /**
     * AJAX: pobranie ID produktów z danej kategorii.
     */
    public function get_products_by_category(): void
    {
        $categoryId = (int) \Shared\Helpers\Helpers::get( 'category_id' );
        $products = $this->repository->getProductsByCategory( $categoryId );

        echo json_encode( [ 'status' => 'ok', 'products' => $products ] );
        exit;
    }
}
