<?php

declare(strict_types=1);

namespace Plugin\tnt_mcp\src\Mcp\Settings;

use JTL\Backend\Settings\Item;
use JTL\Backend\Settings\SectionFactory;
use JTL\DB\DbInterface;
use JTL\DB\SqlObject;
use JTL\L10n\GetText;
use JTL\Services\JTL\AlertServiceInterface;
use JTL\Smarty\JTLSmarty;
use RuntimeException;

/**
 * Generic "what is this setting" metadata for `describe_setting`. `conf` rows are described using
 * the shop's OWN localized strings — {@see \JTL\Backend\Settings\Sections\Base::load()} hydrates
 * an {@see Item} from `teinstellungenconf`, and {@see GetText::localizeConfig()} fills in
 * label/description from the shop's own `.mo` files (`cWertName . '_name'` /
 * `cWertName . '_desc'`) — so zero text is duplicated into settings.yaml. `list` rows have no such
 * metadata source (no teinstellungenconf row), so they fall back to the registry's own
 * title/summary/fields — an honest, minimal description rather than a fabricated one.
 */
final class SettingDescriber
{
    /**
     * Input types for which {@see \JTL\Backend\Settings\Sections\Base::setConfigValues()} populates
     * the Item's option list. For every other type the shop leaves the typed `Item::$values`
     * property UNINITIALISED, so calling `getValues()` fatals ("must not be accessed before
     * initialization") — hence we only read it for these types and report `null` otherwise.
     */
    private const VALUE_BEARING_INPUT_TYPES = ['selectbox', 'listbox', 'selectkdngrp'];


    public function __construct(
        private readonly DbInterface $db,
        private readonly JTLSmarty $smarty,
        private readonly GetText $getText,
        private readonly AlertServiceInterface $alertService,
    ) {
    }

    /** @return array<string,mixed> */
    public function describe(SettingRow $row): array
    {
        if ($row->conf !== null) {
            return $this->describeConf($row, $row->conf);
        }
        if ($row->list !== null) {
            return $this->describeList($row, $row->list);
        }

        throw new RuntimeException('setting "' . $row->key . '" declares neither conf nor list');
    }

    /** @return array<string,mixed> */
    private function describeConf(SettingRow $row, SettingConf $conf): array
    {
        $manager = new McpSettingsManager($this->db, $this->smarty, $this->getText, $this->alertService);
        $section = (new SectionFactory())->getSection($conf->section, $manager);

        $sql = new SqlObject();
        $sql->setWhere('ec.cWertName = :nm');
        $sql->addParam('nm', $conf->name);
        $section->load($sql);

        $item = null;
        foreach ($section->getItems() as $candidate) {
            if ($candidate->getValueName() === $conf->name) {
                $item = $candidate;
                break;
            }
        }
        if (!$item instanceof Item) {
            throw new RuntimeException(
                'setting "' . $row->key . '" not found in shop config (cWertName=' . $conf->name . ')',
            );
        }

        return [
            'key'         => $row->key,
            'title'       => $row->title,
            'summary'     => $row->summary,
            'label'       => $item->getName(),
            'description' => $item->getDescription(),
            'input_type'  => $item->getInputType(),
            'values'      => \in_array($item->getInputType(), self::VALUE_BEARING_INPUT_TYPES, true)
                ? $item->getValues()
                : null,
            'current'     => $item->getCurrentValue(),
            'default'     => $item->getDefaultValue(),
        ];
    }

    /** @return array<string,mixed> */
    private function describeList(SettingRow $row, SettingList $list): array
    {
        return [
            'key'     => $row->key,
            'title'   => $row->title,
            'summary' => $row->summary,
            'table'   => $list->table,
            'fields'  => $list->fields,
        ];
    }
}
