<?php

// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedNamespaceFound -- APD is the established namespace shared with the Pro add-on and retained for backward compatibility.
namespace APD\Support;

use APD\Repositories\UserDesignRepository;
use APD\Support\PricingSnapshot;
use WC_Order;
use WC_Order_Item_Product;

defined('ABSPATH') || exit;

class ProductionPackBuilder
{
    public const STATUS_PENDING = 'pending';
    public const STATUS_IN_PROGRESS = 'in_progress';
    public const STATUS_PRODUCED = 'produced';
    public const STATUS_DELIVERED = 'delivered';

    public static function statusOptions() : array
    {
        return [
            self::STATUS_PENDING => __('To produce', 'asuka-product-designer'),
            self::STATUS_IN_PROGRESS => __('In progress', 'asuka-product-designer'),
            self::STATUS_PRODUCED => __('Produced', 'asuka-product-designer'),
            self::STATUS_DELIVERED => __('Delivered / approved', 'asuka-product-designer'),
        ];
    }

    public static function normalizeStatus(string $status) : string
    {
        $status = sanitize_key($status);
        return array_key_exists($status, self::statusOptions()) ? $status : self::STATUS_PENDING;
    }

    public static function statusLabel(string $status) : string
    {
        $status = self::normalizeStatus($status);
        return self::statusOptions()[$status] ?? self::statusOptions()[self::STATUS_PENDING];
    }

    public static function buildExportUrl(int $orderId, int $itemId, string $export) : string
    {
        $base = add_query_arg([
            'action' => 'apd_export_production_pack',
            'order_id' => $orderId,
            'item_id' => $itemId,
            'export' => sanitize_key($export),
        ], admin_url('admin-post.php'));

        return wp_nonce_url($base, 'apd_export_production_pack_' . $orderId . '_' . $itemId . '_' . sanitize_key($export));
    }

    public static function buildStatusUrl(int $orderId, int $itemId, string $status, string $redirect = '') : string
    {
        $args = [
            'action' => 'apd_update_production_status',
            'order_id' => $orderId,
            'item_id' => $itemId,
            'status' => self::normalizeStatus($status),
        ];
        if ($redirect !== '') {
            $args['redirect'] = rawurlencode($redirect);
        }

        $base = add_query_arg($args, admin_url('admin-post.php'));
        return wp_nonce_url($base, 'apd_update_production_status_' . $orderId . '_' . $itemId . '_' . self::normalizeStatus($status));
    }

    public function build(WC_Order_Item_Product $item, ?WC_Order $order = null) : array
    {
        $order ??= wc_get_order($item->get_order_id());

        $orderId = $order instanceof WC_Order ? (int) $order->get_id() : 0;
        $itemId = (int) $item->get_id();
        $configId = absint($item->get_meta('_apd_config_id', true));
        $productId = absint($item->get_meta('_apd_product_id', true));
        $variationId = absint($item->get_meta('_apd_variation_id', true));
        $userDesignId = absint($item->get_meta('_apd_user_design_id', true));
        $previewUrl = esc_url_raw((string) $item->get_meta('_apd_preview_url', true));
        $resumeUrl = esc_url_raw((string) $item->get_meta('_apd_resume_url', true));
        $status = self::normalizeStatus((string) $item->get_meta('_apd_production_status', true));
        $productionNotes = trim((string) $item->get_meta('_apd_production_notes', true));
        $rawDesign = (string) $item->get_meta('_apd_design_json', true);
        $rawState = (string) $item->get_meta('_apd_state_json', true);
        $summary = Json::decode((string) $item->get_meta('_apd_design_summary', true), []);
        $priceBreakdown = PricingSnapshot::normalize((string) ($item->get_meta('_apd_pricing_payload', true) ?: $item->get_meta('_apd_price_breakdown', true)), (float) $item->get_meta('_apd_price_base', true));
        $variationAttributes = Json::decode((string) $item->get_meta('_apd_variation_attributes', true), []);
        $priceBase = (float) ($priceBreakdown['base_price'] ?? $item->get_meta('_apd_price_base', true));
        $priceAdjustment = (float) ($priceBreakdown['adjustment_total'] ?? $item->get_meta('_apd_price_adjustment', true));
        $priceTotal = (float) ($priceBreakdown['final_price'] ?? $item->get_meta('_apd_price_total', true));

        $repo = new UserDesignRepository();
        $userDesign = $userDesignId > 0 ? $repo->find($userDesignId) : [];
        $design = Json::decode($rawDesign, []);
        if ($design === [] && is_array($userDesign['designJson'] ?? null)) {
            $design = $userDesign['designJson'];
        }

        $state = Json::decode($rawState, []);
        if ($state === [] && is_array($userDesign['stateJson'] ?? null)) {
            $state = $userDesign['stateJson'];
        }

        $summary = is_array($summary) && $summary !== [] ? $summary : DesignSummary::build($design, $state);
        $productionData = is_array($userDesign['productionData'] ?? null) ? $userDesign['productionData'] : [];
        if ($resumeUrl === '' && is_string($productionData['resumeUrl'] ?? null)) {
            $resumeUrl = esc_url_raw((string) $productionData['resumeUrl']);
        }
        if ($previewUrl === '' && ! empty($userDesign['previewUrls'][0]) && is_string($userDesign['previewUrls'][0])) {
            $previewUrl = esc_url_raw((string) $userDesign['previewUrls'][0]);
        }

        $analysis = $this->analyze($design, $state, $summary, $productionData, $productionNotes);

        return [
            'isCustomized' => $configId > 0 || $userDesignId > 0 || $previewUrl !== '' || $rawDesign !== '' || $rawState !== '',
            'orderId' => $orderId,
            'itemId' => $itemId,
            'itemName' => $item->get_name(),
            'quantity' => (int) $item->get_quantity(),
            'dateCreated' => $order instanceof WC_Order && $order->get_date_created() ? $order->get_date_created()->date_i18n(get_option('date_format') . ' ' . get_option('time_format')) : '',
            'customerId' => $order instanceof WC_Order ? (int) $order->get_user_id() : 0,
            'customerName' => $order instanceof WC_Order ? trim($order->get_formatted_billing_full_name()) : '',
            'orderStatus' => $order instanceof WC_Order ? (string) $order->get_status() : '',
            'productionStatus' => $status,
            'productionStatusLabel' => self::statusLabel($status),
            'productionNotes' => $productionNotes,
            'configId' => $configId,
            'configTitle' => (string) $item->get_meta('_apd_config_title', true),
            'productId' => $productId,
            'productTitle' => (string) $item->get_meta('_apd_product_title', true),
            'productSku' => (string) $item->get_meta('_apd_product_sku', true),
            'variationId' => $variationId,
            'variationLabel' => (string) $item->get_meta('_apd_variation_label', true),
            'variationAttributes' => is_array($variationAttributes) ? $variationAttributes : [],
            'userDesignId' => $userDesignId,
            'previewUrl' => $previewUrl,
            'resumeUrl' => $resumeUrl,
            'price' => [
                'base' => $priceBase,
                'adjustment' => $priceAdjustment,
                'total' => $priceTotal,
                'breakdown' => is_array($priceBreakdown) ? $priceBreakdown : [],
            ],
            'summary' => $summary,
            'analysis' => $analysis,
            'productionData' => $productionData,
            'design' => $design,
            'state' => $state,
            'downloads' => [
                'worksheet' => self::buildExportUrl($orderId, $itemId, 'worksheet'),
                'pack' => self::buildExportUrl($orderId, $itemId, 'pack'),
                'summary' => self::buildExportUrl($orderId, $itemId, 'summary'),
                'design' => self::buildExportUrl($orderId, $itemId, 'design'),
                'state' => self::buildExportUrl($orderId, $itemId, 'state'),
            ],
        ];
    }

    protected function analyze(array $design, array $state, array $summary, array $productionData, string $productionNotes = '') : array
    {
        $views = is_array($design['views']['views'] ?? null) ? $design['views']['views'] : [];
        $objectsByView = [];
        if (is_array($state['objects']['byView'] ?? null)) {
            $objectsByView = $state['objects']['byView'];
        } elseif (is_array($design['objects']['byView'] ?? null)) {
            $objectsByView = $design['objects']['byView'];
        }

        $viewDetails = [];
        $objectTypes = [];
        $colors = [];
        $texts = [];
        $totalObjects = 0;

        foreach ($views as $view) {
            if (! is_array($view)) {
                continue;
            }

            $viewId = (string) ($view['id'] ?? '');
            $viewName = (string) ($view['name'] ?? $viewId);
            $viewObjects = is_array($objectsByView[$viewId] ?? null) ? $objectsByView[$viewId] : [];
            $typeCounts = [];
            foreach ($viewObjects as $object) {
                if (! is_array($object)) {
                    continue;
                }
                $totalObjects++;
                $type = $this->normalizeObjectType((string) ($object['type'] ?? 'Object'));
                if ($type !== '') {
                    $objectTypes[$type] = true;
                    $typeCounts[$type] = (int) ($typeCounts[$type] ?? 0) + 1;
                }
                foreach (['fill', 'stroke', 'backgroundColor', 'textBackgroundColor'] as $colorKey) {
                    $value = trim((string) ($object[$colorKey] ?? ''));
                    if ($value === '' || $value === 'transparent' || $value === 'none') {
                        continue;
                    }
                    $colors[$value] = true;
                }
                $text = trim((string) ($object['text'] ?? ''));
                if ($text !== '') {
                    $texts[$text] = true;
                }
            }

            $viewDetails[] = [
                'id' => $viewId,
                'name' => $viewName !== '' ? $viewName : $viewId,
                'width' => isset($view['width']) ? (float) $view['width'] : 0,
                'height' => isset($view['height']) ? (float) $view['height'] : 0,
                'unit' => (string) ($view['unit'] ?? 'px'),
                'dpi' => isset($view['dpi']) ? (int) $view['dpi'] : 0,
                'objectCount' => count($viewObjects),
                'objectTypes' => $typeCounts,
            ];
        }

        $printingMethods = [];
        $catalogPrinting = $state['catalog']['printingMethods'] ?? [];
        if (is_array($catalogPrinting)) {
            foreach ($catalogPrinting as $method) {
                if (! is_array($method)) {
                    continue;
                }
                $label = trim((string) ($method['label'] ?? $method['name'] ?? $method['id'] ?? ''));
                if ($label !== '') {
                    $printingMethods[$label] = true;
                }
            }
        }

        return [
            'viewDetails' => $viewDetails,
            'viewCount' => count($viewDetails),
            'objectCount' => $totalObjects > 0 ? $totalObjects : absint($summary['objectCount'] ?? 0),
            'objectTypes' => array_values(array_keys($objectTypes ?: array_fill_keys((array) ($summary['objectTypes'] ?? []), true))),
            'colors' => array_values(array_keys($colors ?: array_fill_keys((array) ($summary['colors'] ?? []), true))),
            'texts' => array_values(array_keys($texts ?: array_fill_keys((array) ($summary['texts'] ?? []), true))),
            'catalogElements' => array_values((array) ($summary['catalogElements'] ?? [])),
            'catalogDesigns' => array_values((array) ($summary['catalogDesigns'] ?? [])),
            'printingMethods' => array_values(array_keys($printingMethods)),
            'notes' => $productionNotes !== '' ? $productionNotes : (is_string($productionData['notes'] ?? null) ? trim((string) $productionData['notes']) : ''),
        ];
    }

    protected function normalizeObjectType(string $type) : string
    {
        $type = trim($type);
        if ($type === '') {
            return '';
        }

        $map = [
            'Textbox' => __('Text', 'asuka-product-designer'),
            'IText' => __('Text', 'asuka-product-designer'),
            'Text' => __('Text', 'asuka-product-designer'),
            'Image' => __('Image', 'asuka-product-designer'),
            'image' => __('Image', 'asuka-product-designer'),
            'Rect' => __('Shape', 'asuka-product-designer'),
            'Circle' => __('Shape', 'asuka-product-designer'),
            'Triangle' => __('Shape', 'asuka-product-designer'),
            'Polygon' => __('Shape', 'asuka-product-designer'),
            'Path' => __('Path', 'asuka-product-designer'),
        ];

        return $map[$type] ?? $type;
    }
}
