<?php
namespace Components\Models;

/**
 * Coupons model supporting multiple platforms.
 * - Table structure differs on Zen Cart vs. other systems.
 * - We ignore Zen Cart–only fields when MH_PLATFORM != 'zencart' to avoid DB errors.
 */
class Coupon extends BaseModel
{
    protected static string $table = 'TABLE_COUPONS';
    protected static string $primaryKey = 'coupon_id';

    // Optional model-level blueprint (resolved by CrudController)
    protected static string $blueprint = 'coupon.yaml';

    /**
     * List of columns that exist only on Zen Cart installations.
     * These will be stripped on save when MH_PLATFORM != 'zencart'.
     */
    protected static array $zenCartOnly = [
        'restrict_to_products', // varchar(255) in zencart vs text in others — keep key but safe to strip if platform mismatch
        'restrict_to_categories', // varchar(255) in zencart vs text in others
        'restrict_to_customers', // text exists in both; kept here for safety if schema differences
        'coupon_zone_restriction',
        'coupon_calc_base',
        'coupon_order_limit',
        'coupon_is_valid_for_sales',
        'coupon_product_count',
    ];

    /**
     * Hook to sanitize data before saving.
     * - On non-ZenCart platforms, remove ZenCart-only columns from the payload.
     * - Also coerce date defaults to platform expectations when fields are empty.
     * - Strip i18n fields that belong to coupons_description when present in form payload.
     */
    protected function filterAttributesForSave(array $data): array
    {
        $platform = function_exists('mh_cfg') ? (string) mh_cfg('MH_PLATFORM', '') : '';
        $isZen = strtolower($platform) === 'zencart';

        if (!$isZen) {
            foreach (self::$zenCartOnly as $col) {
                if (array_key_exists($col, $data)) {
                    unset($data[$col]);
                }
            }
        }

        // Remove translation arrays from main table payload
        foreach (['coupon_name','coupon_description'] as $tx) {
            if (array_key_exists($tx, $data)) { unset($data[$tx]); }
        }

        // Map UI helper fields to canonical coupon_amount based on coupon_type
        $type = strtoupper(trim((string)($data['coupon_type'] ?? '')));
        $amtPercent = isset($data['coupon_amount_percent']) ? (string)$data['coupon_amount_percent'] : '';
        $amtFixed = isset($data['coupon_amount_fixed']) ? (string)$data['coupon_amount_fixed'] : '';
        $setAmount = null;
        if ($type === 'P') {
            // percentage as-is (e.g., 10 => 10%)
            if ($amtPercent === '' && isset($data['coupon_amount'])) { $amtPercent = (string)$data['coupon_amount']; }
            if ($amtPercent !== '') {
                $num = is_numeric($amtPercent) ? (float)$amtPercent : (float)preg_replace('/[^0-9.\-]/', '', $amtPercent);
                $setAmount = number_format($num, 4, '.', '');
            } else {
                $setAmount = '0.0000';
            }
        } elseif ($type === 'F') {
            // fixed currency amount
            if ($amtFixed === '' && isset($data['coupon_amount'])) { $amtFixed = (string)$data['coupon_amount']; }
            if ($amtFixed !== '') {
                $num = is_numeric($amtFixed) ? (float)$amtFixed : (float)preg_replace('/[^0-9.\-]/', '', $amtFixed);
                $setAmount = number_format($num, 4, '.', '');
            } else {
                $setAmount = '0.0000';
            }
        } elseif ($type === 'S') {
            // free shipping -> amount not used
            $setAmount = '0.0000';
        }
        if ($setAmount !== null) {
            $data['coupon_amount'] = $setAmount;
        }
        // Drop UI-only fields
        unset($data['coupon_amount_percent'], $data['coupon_amount_fixed']);

        // Normalize date defaults if empty
        // ZenCart uses '0001-01-01 00:00:00', others often use '0000-00-00 00:00:00'
        $dateZeroOther = '0000-00-00 00:00:00';
        $dateZeroZen = '1000-01-01 00:00:00';
        $startKey = 'coupon_start_date';
        $endKey = 'coupon_expire_date';
        $createdKey = 'date_created';
        $modifiedKey = 'date_modified';

        foreach ([$startKey, $endKey, $createdKey, $modifiedKey] as $k) {
            if (!array_key_exists($k, $data) || $data[$k] === '' || $data[$k] === null) {
                $data[$k] = $isZen ? $dateZeroZen : $dateZeroOther;
            }
        }

        return $data;
    }

    public function icon() {
        return self::getIcon($this->attributes['coupon_type'] ?? '');
    }

    public static function getIcon(string $type): array
    {
        switch (strtoupper($type)) {
            case 'F':
                return ['svg' => \Components\Base::SVG_OUTLINE_MONEY, 'color' => self::getCouponTypeColor('F'), 'size' => 'sm', 'variant' => 'solid'];
            case 'P':
                return ['svg' => \Components\Base::SVG_VOUCHER, 'color' => self::getCouponTypeColor('P'), 'size' => 'sm', 'variant' => 'solid'];
            case 'S':
                return ['svg' => \Components\Base::SVG_OUTLINE_TRUCK, 'color' => self::getCouponTypeColor('S'), 'size' => 'sm', 'variant' => 'solid'];
            default:
                return ['svg' => \Components\Base::SVG_MINUS, 'color' => 'gray', 'size' => 'sm', 'variant' => 'solid'];
        }
    }

    static public function getCouponTypeColor($type) {
        $map = [
            'F' => 'green',
            'P' => 'orange',
            'S' => 'blue',
        ];
        return $map[$type] ?? 'gray';
    }

    /**
     * Default values for new coupon records (used by CrudController on GET/new).
     */
    public static function getNewDefaults(): array
    {
        $defaults = [];
        try {
            $now = new \DateTime('now');
            $defaults['coupon_start_date'] = $now->format('Y-m-d H:i:s');
            $exp = clone $now;
            $exp->modify('+14 days');
            $defaults['coupon_expire_date'] = $exp->format('Y-m-d H:i:s');
        } catch (\Throwable $e) { /* ignore */ }
        return $defaults;
    }

    /**
     * Augment form values with i18n translations from coupons_description so they can be edited in the same dialog.
     * @param array $values
     * @return array
     */
    public function augmentFormValues(array $values): array
    {
        $id = (int)($values[static::$primaryKey] ?? $this->{static::$primaryKey} ?? 0);
        if ($id > 0) {
            try {
                $all = CouponDescription::forCoupon($id);
                $names = [];
                $descs = [];
                foreach ($all as $lid => $row) {
                    $names[$lid] = (string)($row['coupon_name'] ?? '');
                    $descs[$lid] = (string)($row['coupon_description'] ?? '');
                }
                $values['coupon_name'] = $names;
                $values['coupon_description'] = $descs;
            } catch (\Throwable $e) { /* ignore */ }
        }
        // Prefill UI helper fields for amount based on coupon_type
        try {
            $type = strtoupper(trim((string)($values['coupon_type'] ?? $this->coupon_type ?? '')));
            $amt = (string)($values['coupon_amount'] ?? $this->coupon_amount ?? '');
            if ($amt !== '') {
                if ($type === 'P') {
                    $values['coupon_amount_percent'] = $amt;
                } elseif ($type === 'F') {
                    $values['coupon_amount_fixed'] = $amt;
                }
            }
        } catch (\Throwable $e) { /* ignore */ }
        return $values;
    }

    /**
     * Persist translations posted as coupon_name[langId] and coupon_description[langId].
     */
    public function afterSave(array $post): void
    {
        $id = (int)($this->{static::$primaryKey} ?? 0);
        if ($id <= 0) return;
        $names = isset($post['coupon_name']) && is_array($post['coupon_name']) ? $post['coupon_name'] : [];
        $descs = isset($post['coupon_description']) && is_array($post['coupon_description']) ? $post['coupon_description'] : [];
        $map = [];
        // Prefer live env language list for stable ids
        $langIds = [];
        if (function_exists('mh_get_language_list')) {
            try {
                foreach ((array)\mh_get_language_list() as $lg) {
                    if (is_array($lg) && isset($lg['id'])) { $langIds[] = (int)$lg['id']; }
                }
            } catch (\Throwable $e) { $langIds = []; }
        }
        // If not available, derive from submitted keys
        if (empty($langIds)) {
            $langIds = array_unique(array_map('intval', array_merge(array_keys($names), array_keys($descs))));
        }
        foreach ($langIds as $lid) {
            $lid = (int)$lid; if ($lid <= 0) continue;
            $nm = isset($names[$lid]) ? trim((string)$names[$lid]) : '';
            $dc = isset($descs[$lid]) ? (string)$descs[$lid] : '';
            if ($nm === '' && $dc === '') continue; // nothing to store
            $map[$lid] = [ 'coupon_name' => $nm, 'coupon_description' => $dc ];
        }
        if (!empty($map)) {
            try { CouponDescription::syncForCoupon($id, $map); } catch (\Throwable $e) { /* ignore */ }
        }
    }

    public static function paginate(int $perPage = 10, int $page = 1, string $search = '', array $searchCols = [], array $filters = []): array
    {
        if (self::isDev()) return ['items' => [], 'total' => 0];

        $table = static::table();
        $where = $table . ".coupon_code NOT LIKE 'template_%'";
        $join = "";

        if (isset($filters['template_coupon_id']) && (int)$filters['template_coupon_id'] > 0 && defined('TABLE_MAILBEEZ_TRACKING_COUPONS')) {
            $templateId = (int)$filters['template_coupon_id'];
            $join = " JOIN " . TABLE_MAILBEEZ_TRACKING_COUPONS . " t ON " . $table . ".coupon_id = t.coupon_id";
            $where .= " AND t.template_coupon_id = " . $templateId;
        }

        if ($search !== '' && !empty($searchCols)) {
            $clauses = [];
            foreach ($searchCols as $col) {
                $clauses[] = $table . "." . $col . " LIKE '%" . \mh_db_input($search) . "%'";
            }
            $where .= " AND (" . implode(" OR ", $clauses) . ")";
        }

        $countSql = "SELECT COUNT(*) as total FROM " . $table . $join . " WHERE " . $where;
        $cq = \mh_db_query($countSql);
        $res = \mh_db_fetch_array($cq);
        $total = (int)($res['total'] ?? 0);
        \mh_db_free_result($cq);

        $offset = max(0, ($page - 1) * $perPage);

        $sql = "SELECT " . $table . ".* FROM " . $table . $join . " WHERE " . $where . " ORDER BY " . $table . "." . static::pk() . " DESC LIMIT " . (int)$offset . ", " . (int)$perPage;
        $q = \mh_db_query($sql);

        $items = [];
        while ($row = \mh_db_fetch_array($q)) {
            $items[] = new static($row);
        }
        \mh_db_free_result($q);

        return [
            'items' => $items,
            'total' => $total,
        ];
    }

    /**
     * Dynamic select options for coupon_id (Coupon)
     * Returns rich option data including identity for CollectionIdentity rendering.
     *
     * @param mixed $includeNone Include "no coupon" option (if not boolean, defaults to true)
     * @return array<int|string, array{label: string, identity: array}>
     */
    public static function listOptions($includeNone = true): array
    {
        if (!is_bool($includeNone)) {
            $includeNone = true;
        }

        $options = [];

        try {
            $prov = \Components\Data\DataRegistry::templateCoupons();
            $rows = $prov ? $prov->templates($includeNone) : [];
        } catch (\Throwable $e) {
            $rows = [];
        }

        foreach ((array)$rows as $row) {
            if (!is_array($row)) continue;

            $id = $row['id'] ?? null;
            if ($id === null) continue;

            $code = $row['code'] ?? '';
            $codeMain = $row['codeMain'] ?? str_replace('template_', '', $code);
            $typeLabel = $row['typeLabel'] ?? '';
            $type = $row['type'] ?? '';

            $label = $id < 1 ? \mh_lng('MAILBEEZ_COUPON_TYPE_NONE', 'no coupon') : $codeMain . ' - ' . $typeLabel;

            $options[$id] = [
                'label'    => $label,
                'identity' => self::getIcon($type),
            ];
        }

        return $options;
    }
}
