#!/usr/bin/env python3
"""Check the basic structure of one Plugin before host validation."""

import re
import sys
from pathlib import Path, PurePosixPath


ROOT = Path(__file__).resolve().parents[1]
ID_RE = re.compile(r"[a-z0-9]+(?:-[a-z0-9]+)*(?:\.[a-z0-9]+(?:-[a-z0-9]+)*)*\Z")


def fail(message: str) -> None:
    raise SystemExit(f"Plugin check failed: {message}")


def member(source: Path, value: object) -> None:
    if not isinstance(value, str) or not value or "\\" in value:
        fail(f"invalid member path: {value!r}")
    path = PurePosixPath(value)
    if path.is_absolute() or value != path.as_posix() or any(part in (".", "..") for part in path.parts):
        fail(f"member path must stay inside the Plugin: {value}")
    target = source.joinpath(*path.parts)
    if target.is_symlink() or not target.is_file():
        fail(f"missing regular file: {value}")


def section(text: str, name: str) -> str:
    if not name:
        return text.split("\n[", 1)[0]
    match = re.search(rf"^\[{re.escape(name)}\]\s*$", text, re.MULTILINE)
    if not match:
        return ""
    return re.split(r"^\[", text[match.end():], maxsplit=1, flags=re.MULTILINE)[0]


def quoted(block: str, key: str) -> str:
    match = re.search(rf'^\s*{re.escape(key)}\s*=\s*"([^"\n]*)"', block, re.MULTILINE)
    return match.group(1) if match else ""


def main() -> None:
    if len(sys.argv) != 2 or not ID_RE.fullmatch(sys.argv[1]):
        fail("usage: bin/check PLUGIN_ID")
    source = ROOT / "plugins" / sys.argv[1]
    if not source.is_dir() or source.is_symlink():
        fail(f"missing Plugin folder: {source}")
    for path in source.rglob("*"):
        if path.is_symlink():
            fail(f"symlinks are not allowed: {path.relative_to(source)}")
    try:
        manifest = (source / "ele-plugin.toml").read_text(encoding="utf-8")
    except OSError as error:
        fail(f"cannot read ele-plugin.toml: {error}")
    identity = section(manifest, "")
    if quoted(identity, "schema") != "ele.plugin/v1" or quoted(identity, "id") != sys.argv[1]:
        fail("manifest schema or ID does not match the Plugin folder")
    for field in ("name", "version", "tagline"):
        if not quoted(identity, field).strip():
            fail(f"manifest {field} needs text")
    if not re.search(r"^\s*description\s*=\s*\S", identity, re.MULTILINE):
        fail("manifest description needs text")
    if not quoted(section(manifest, "publisher"), "name").strip():
        fail("manifest publisher.name needs text")
    member(source, quoted(identity, "icon"))
    files_match = re.search(r"^\s*files\s*=\s*\[([^\]]*)\]", section(manifest, "license"), re.MULTILINE)
    licenses = re.findall(r'"([^"\n]+)"', files_match.group(1)) if files_match else []
    if not licenses:
        fail("manifest license.files needs at least one file")
    for path in licenses:
        member(source, path)
    runtime = section(manifest, "runtime")
    if runtime:
        member(source, quoted(runtime, "module"))
    browser = section(manifest, "browser")
    if browser:
        member(source, quoted(browser, "entry"))
    print(f"Basic Plugin structure passed: {sys.argv[1]}")
    print("ELE validates the full package during staging.")


if __name__ == "__main__":
    main()
