#!/usr/bin/env python3
"""Add explicit Alibaba Cloud MQTT auth-mode support to a Store release."""

import argparse
import shutil
from pathlib import Path


def replace_once(text: str, old: str, new: str, label: str) -> str:
    count = text.count(old)
    if count != 1:
        raise ValueError(f"{label}: expected one match, found {count}")
    return text.replace(old, new, 1)


def patch_mqtt_config(path: Path) -> str:
    text = path.read_text(encoding="utf-8")
    if "'ali_mqtt_auth_mode'," in text and "'authMode' =>" in text:
        return text
    text = replace_once(
        text,
        "        'ali_mqtt_disjunctor',\n",
        "        'ali_mqtt_disjunctor',\n        'ali_mqtt_auth_mode',\n",
        "MqttConfig config key",
    )
    text = replace_once(
        text,
        "                'disjunctor' => $config['ali_mqtt_disjunctor'] ?? 0,\n",
        "                'disjunctor' => $config['ali_mqtt_disjunctor'] ?? 0,\n"
        "                'authMode' => $config['ali_mqtt_auth_mode'] ?? 'signature',\n",
        "MqttConfig resolved auth mode",
    )
    text = replace_once(
        text,
        "    public function username() {\n"
        "        $config = $this->all();\n"
        "        return 'Signature|' . $config['accessKey'] . '|' . $config['instanceId'];\n"
        "    }\n",
        "    public function username() {\n"
        "        $config = $this->all();\n"
        "        $prefixes = [\n"
        "            'signature' => 'Signature',\n"
        "            'device-credential' => 'DeviceCredential',\n"
        "        ];\n"
        "        if (!isset($prefixes[$config['authMode']])) {\n"
        "            throw new \\RuntimeException('Unsupported Alibaba Cloud MQTT auth mode');\n"
        "        }\n"
        "        return $prefixes[$config['authMode']] . '|' . $config['accessKey'] . '|' . $config['instanceId'];\n"
        "    }\n",
        "MqttConfig username",
    )
    return text


def patch_mqtt_server(path: Path) -> str:
    text = path.read_text(encoding="utf-8")
    if "private $authMode" in text and "'ali_mqtt_auth_mode'" in text:
        return text
    text = replace_once(
        text,
        "    private $disjunctor = 0;\n",
        "    private $disjunctor = 0;\n    private $authMode = 'signature';\n",
        "MQTTServer property",
    )
    text = replace_once(
        text,
        "$config_keys = ['ali_mqtt_disjunctor','ali_mqtt_accessKey'",
        "$config_keys = ['ali_mqtt_disjunctor','ali_mqtt_auth_mode','ali_mqtt_accessKey'",
        "MQTTServer config key",
    )
    text = replace_once(
        text,
        "            $this->disjunctor = $ali_mqtt['ali_mqtt_disjunctor'];\n",
        "            $this->disjunctor = $ali_mqtt['ali_mqtt_disjunctor'];\n"
        "            $this->authMode = $ali_mqtt['ali_mqtt_auth_mode'] ?? 'signature';\n",
        "MQTTServer auth assignment",
    )
    text = replace_once(
        text,
        "            'disjunctor' => $this->disjunctor,\n",
        "            'disjunctor' => $this->disjunctor,\n"
        "            'authMode' => $this->authMode,\n",
        "MQTTServer config output",
    )
    text = replace_once(
        text,
        "    protected function username() {\n"
        "        return 'Signature|' . $this->accessKey . '|' . $this->instanceId;\n"
        "    }\n",
        "    protected function username() {\n"
        "        $prefixes = [\n"
        "            'signature' => 'Signature',\n"
        "            'device-credential' => 'DeviceCredential',\n"
        "        ];\n"
        "        if (!isset($prefixes[$this->authMode])) {\n"
        "            throw new \\RuntimeException('Unsupported Alibaba Cloud MQTT auth mode');\n"
        "        }\n"
        "        return $prefixes[$this->authMode] . '|' . $this->accessKey . '|' . $this->instanceId;\n"
        "    }\n",
        "MQTTServer username",
    )
    return text


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--project-root", type=Path, required=True)
    parser.add_argument("--backup-dir", type=Path, required=True)
    args = parser.parse_args()

    targets = {
        args.project_root / "extend/mqtt/MqttConfig.php": patch_mqtt_config,
        args.project_root / "extend/mqtt/MQTTServer.php": patch_mqtt_server,
    }
    args.backup_dir.mkdir(parents=True, exist_ok=True)
    for path, patcher in targets.items():
        if not path.is_file():
            raise FileNotFoundError(path)
        patched = patcher(path)
        backup = args.backup_dir / (path.name + ".before-mqtt-auth")
        if not backup.exists():
            shutil.copy2(path, backup)
        path.write_text(patched, encoding="utf-8")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
