<?php
namespace Components\Models;

use Components\Support\Palette;
use Components\Ui\Badge;

class Review extends BaseModel
{
    protected static string $table = 'TABLE_REVIEWS';
    protected static string $primaryKey = 'reviews_id';

    protected static string $blueprint = 'review.yaml';

    protected static ?string $statusColumnCache = null;

    public static function getNewDefaults(): array
    {
        return [
            'reviews_rating' => '5',
            'reviews_read' => '0',
            'review_status' => '1',
            'reviews_text' => [],
        ];
    }

    public function augmentFormValues(array $values): array
    {
        $statusColumn = static::statusColumn();
        $statusValue = $values[$statusColumn] ?? ($values['reviews_status'] ?? ($values['status'] ?? '1'));
        $values['review_status'] = ((int)$statusValue > 0) ? '1' : '0';

        $id = (int)($values[static::pk()] ?? 0);
        if ($id > 0) {
            $rows = ReviewDescription::forReview($id);
            $texts = [];
            foreach ($rows as $lid => $row) {
                $texts[(int)$lid] = (string)($row['reviews_text'] ?? '');
            }
            $values['reviews_text'] = $texts;
        } else {
            $values['reviews_text'] = [];
        }

        return $values;
    }

    protected function filterAttributesForSave(array $data): array
    {
        $statusColumn = static::statusColumn();
        $alternateStatusColumn = ($statusColumn === 'reviews_status') ? 'status' : 'reviews_status';

        if (array_key_exists('review_status', $data)) {
            $data[$statusColumn] = $this->normalizeToggleToIntString($data['review_status']);
        }
        unset($data['review_status']);
        unset($data[$alternateStatusColumn]);
        unset($data['reviews_text']);

        foreach (['products_id', 'customers_id', 'reviews_rating', 'reviews_read'] as $intColumn) {
            if (!array_key_exists($intColumn, $data)) {
                continue;
            }
            if ($data[$intColumn] === '' || $data[$intColumn] === null) {
                $data[$intColumn] = ($intColumn === 'customers_id') ? null : '0';
            } else {
                $data[$intColumn] = (string)(int)$data[$intColumn];
            }
        }

        return parent::filterAttributesForSave($data);
    }

    public function afterSave(array $post): void
    {
        $id = (int)($this->attributes[static::pk()] ?? 0);
        if ($id <= 0) {
            return;
        }

        $texts = $post['reviews_text'] ?? [];
        $map = [];

        if (is_array($texts)) {
            foreach ($texts as $lid => $text) {
                $langId = (int)$lid;
                if ($langId <= 0) {
                    continue;
                }
                $value = trim((string)$text);
                if ($value === '') {
                    continue;
                }
                $map[$langId] = $value;
            }
        } elseif (is_string($texts) && trim($texts) !== '') {
            $langId = (int)($_SESSION['languages_id'] ?? 1);
            if ($langId > 0) {
                $map[$langId] = trim($texts);
            }
        }

        if (!empty($map)) {
            ReviewDescription::syncForReview($id, $map);
        }
    }

    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();
        $descTable = ReviewDescription::table();
        $productDescTable = ProductDescription::table();
        $pk = static::pk();
        $statusColumn = static::statusColumn();
        $langId = (int)($_SESSION['languages_id'] ?? 1);

        $where = "1=1";
        if ($search !== '' && !empty($searchCols)) {
            $clauses = [];
            foreach ($searchCols as $col) {
                if ($col === 'reviews_text') {
                    $clauses[] = "rd.reviews_text LIKE '%" . \mh_db_input($search) . "%'";
                } elseif ($col === 'products_name') {
                    $clauses[] = "pd.products_name LIKE '%" . \mh_db_input($search) . "%'";
                } else {
                    $clauses[] = $table . "." . $col . " LIKE '%" . \mh_db_input($search) . "%'";
                }
            }
            $where .= " AND (" . implode(' OR ', $clauses) . ")";
        }
        if (!empty($filters)) {
            $filterStatus = $filters['review_status'] ?? $filters['status'] ?? $filters['reviews_status'] ?? null;
            if ($filterStatus !== null && $filterStatus !== '') {
                if ($filterStatus === 'active') {
                    $where .= " AND " . $table . "." . $statusColumn . " > 0";
                } elseif ($filterStatus === 'inactive') {
                    $where .= " AND " . $table . "." . $statusColumn . " = 0";
                } else {
                    $where .= " AND " . $table . "." . $statusColumn . " = '" . \mh_db_input((string)(int)$filterStatus) . "'";
                }
            }

            if (isset($filters['languages_id']) && $filters['languages_id'] !== '') {
                $where .= " AND rd.languages_id = '" . \mh_db_input((string)(int)$filters['languages_id']) . "'";
            }

            if (isset($filters['reviews_rating']) && $filters['reviews_rating'] !== '') {
                $where .= " AND " . $table . ".reviews_rating = '" . \mh_db_input((string)$filters['reviews_rating']) . "'";
            }
        }

        $join =
            " LEFT JOIN " . $descTable . " rd ON (" . $table . "." . $pk . " = rd.reviews_id AND rd.languages_id = " . $langId . ")" .
            " LEFT JOIN " . $productDescTable . " pd ON (" . $table . ".products_id = pd.products_id AND pd.language_id = " . $langId . ")";

        $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 . ".*, rd.reviews_text, rd.languages_id, pd.products_name, pd.language_id FROM " . $table . $join .
            " WHERE " . $where .
            " ORDER BY " . $table . ".date_added DESC, " . $table . "." . $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,
        ];
    }

    protected static function statusColumn(): string
    {
        if (static::$statusColumnCache !== null) {
            return static::$statusColumnCache;
        }

        $table = static::table();
        $preferred = 'reviews_status';
        $fallback = 'status';

        if (function_exists('mh_db_check_field_exists')) {
            try {
                if (\mh_db_check_field_exists($table, $preferred)) {
                    static::$statusColumnCache = $preferred;
                    return static::$statusColumnCache;
                }
                if (\mh_db_check_field_exists($table, $fallback)) {
                    static::$statusColumnCache = $fallback;
                    return static::$statusColumnCache;
                }
            } catch (\Throwable $e) {
                // ignore and use preferred fallback
            }
        }

        static::$statusColumnCache = $preferred;
        return static::$statusColumnCache;
    }

    /**
     * @param mixed $value
     */
    protected function normalizeToggleToIntString($value): string
    {
        return ($value === 'on' || $value === '1' || $value === 'True' || $value === true) ? '1' : '0';
    }

    /**
     * Determine the current status of a review.
     *
     * @param array|\Components\Models\Review $item Review record or object
     * @return string 'active' or 'inactive'
     */
    public static function getStatus($item): string
    {
        $attrs = ($item instanceof self) ? $item->attributes : $item;
        $statusColumn = static::statusColumn();
        $statusValue = $attrs[$statusColumn] ?? ($attrs['reviews_status'] ?? ($attrs['status'] ?? '1'));
        return ((int)$statusValue > 0) ? 'active' : 'inactive';
    }

    /**
     * Render the status badge for a review.
     *
     * @param array|\Components\Models\Review $item
     * @param array $options Optional overrides for Badge::render
     * @return string HTML
     */
    public static function renderStatusBadge($item, array $options = []): string
    {
        $status = self::getStatus($item);
        return self::renderStatusBadgeByStatus($status, $options);
    }

    /**
     * Render a status badge by status key.
     *
     * @param string $status 'active' or 'inactive'
     * @param array $options Optional overrides for Badge::render
     * @return string HTML
     */
    public static function renderStatusBadgeByStatus(string $status, array $options = []): string
    {
        $all = self::getStatusConfig();
        $cfg = $all[$status] ?? $all['inactive'];

        $badgeOptions = array_merge([
            'class' => Palette::newsletterStateBadgeClass($status),
            'icon_class' => 'size-3.5',
        ], $options);

        return Badge::render($status, $cfg['label'], $badgeOptions);
    }

    /**
     * Get rich status options for UI components like rich_select.
     *
     * @return array<string, array{label: string, identity: array, label_html: string}>
     */
    public static function getStatusOptions(): array
    {
        $options = self::getStatusConfig();
        foreach ($options as $status => &$opt) {
            $opt['label_html'] = self::renderStatusBadgeByStatus($status);
        }
        return $options;
    }

    /**
     * Internal status configuration.
     * @return array
     */
    protected static function getStatusConfig(): array
    {
        return [
            'active' => [
                'label' => \mh_lng('UI_TEXT_STATUS_ACTIVE', 'Active'),
                'identity' => [ 'color' => 'green', 'size' => 'sm', 'variant' => 'soft']
            ],
            'inactive' => [
                'label' => \mh_lng('UI_TEXT_STATUS_INACTIVE', 'Inactive'),
                'identity' => ['color' => 'gray', 'size' => 'sm', 'variant' => 'soft']
            ],
        ];
    }
}
