"""Pytest-tesztek a jmap.py Joomla manifest -> deployed-path mapperhez.

Minden teszt egy szintetikus, minimál kicsomagolt bővítmény-csomagot épít fel
tmp_path alatt (manifest-XML + pár dummy forrásfájl), lefuttatja a mappinget,
és a kapott docroot-fát ellenőrzi a Joomla 3.x installer-szabályok szerint.
"""

from __future__ import annotations

import subprocess
import sys
from pathlib import Path

import pytest

import jmap


def _write(path: Path, content: str = "") -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(content, encoding="utf-8")


def _run(package_dir: Path, out_dir: Path) -> list[jmap.CopyOp]:
    manifest_path = jmap.find_manifest(package_dir)
    ops = jmap.build_operations(manifest_path, out_dir)
    jmap.execute(ops)
    return ops


# ---------------------------------------------------------------------------
# component: site + admin + media + languages
# ---------------------------------------------------------------------------


def test_component_site_admin_media_language(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"

    _write(
        pkg / "com_hello.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3.9.0" method="upgrade">
    <name>com_hello</name>
    <files folder="sitefiles">
        <filename>helloworld.php</filename>
        <folder>controllers</folder>
    </files>
    <administration>
        <files folder="adminfiles">
            <filename>helloworld.php</filename>
        </files>
        <languages folder="adminlang">
            <language tag="en-GB">en-GB/en-GB.com_hello.sys.ini</language>
        </languages>
    </administration>
    <media destination="com_hello" folder="mediafiles">
        <folder>images</folder>
    </media>
    <languages folder="sitelang">
        <language tag="en-GB">en-GB/en-GB.com_hello.ini</language>
    </languages>
</extension>
""",
    )
    _write(pkg / "sitefiles/helloworld.php", "<?php // site")
    _write(pkg / "sitefiles/controllers/foo.php", "<?php // controller")
    _write(pkg / "adminfiles/helloworld.php", "<?php // admin")
    _write(pkg / "mediafiles/images/icon.png", "PNGDATA")
    _write(pkg / "sitelang/en-GB/en-GB.com_hello.ini", "FIELD=Value")
    _write(pkg / "adminlang/en-GB/en-GB.com_hello.sys.ini", "COM_HELLO=Hello")

    _run(pkg, out)

    assert (out / "components/com_hello/helloworld.php").read_text() == "<?php // site"
    assert (out / "components/com_hello/controllers/foo.php").read_text() == "<?php // controller"
    assert (out / "administrator/components/com_hello/helloworld.php").read_text() == "<?php // admin"
    assert (out / "media/com_hello/images/icon.png").read_text() == "PNGDATA"
    assert (out / "language/en-GB/en-GB.com_hello.ini").read_text() == "FIELD=Value"
    assert (out / "administrator/language/en-GB/en-GB.com_hello.sys.ini").read_text() == "COM_HELLO=Hello"


# ---------------------------------------------------------------------------
# component deployed-név-levezetés -- regressziós tesztek a valós
# OneAll Social Login csomagon talált hibára (a <name> emberi megjelenítő-cím
# volt, nem a gépi elemnév; a helyes forrás a <files folder="com_..."> ill.
# a nyelvi fájlnév/scriptfile-mintázat/name-fallback prioritási láncban).
# ---------------------------------------------------------------------------


def test_component_name_from_files_folder_com_prefix(tmp_path: Path) -> None:
    """Elsődleges forrás: <files folder="com_..."> -- a <name> emberi cím, eltér."""
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"
    _write(
        pkg / "manifest.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3">
    <name>Totally Human Display Title</name>
    <files folder="com_realname">
        <file>index.html</file>
    </files>
</extension>
""",
    )
    _write(pkg / "com_realname/index.html", "<html></html>")

    _run(pkg, out)

    assert (out / "components/com_realname/index.html").read_text() == "<html></html>"
    assert not (out / "components/totallyhumandisplaytitle").exists()


def test_component_name_fallback_removes_spaces_not_underscore(tmp_path: Path) -> None:
    """Végső fallback (nincs com_-folder, nincs nyelvi fájl, nincs scriptfile):
    a <name> normalizálása szóköz-ELTÁVOLÍTÁSSAL történik, NEM aláhúzás-cserével.
    """
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"
    _write(
        pkg / "manifest.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3">
    <name>OneAll Social Login</name>
    <files>
        <filename>index.html</filename>
    </files>
</extension>
""",
    )
    _write(pkg / "index.html", "<html></html>")

    _run(pkg, out)

    assert (out / "components/com_oneallsociallogin/index.html").exists()
    assert not (out / "components/com_oneall_social_login").exists()


def test_component_with_embedded_modules_and_plugins_real_pattern(tmp_path: Path) -> None:
    """A valós OneAll Social Login csomag mintázatának replikája: EGYETLEN
    type="component" manifest, ami <files folder="com_..."> -val adja meg a
    deployed-nevet, <file> tag-eket (nem <filename>-t) használ, és beágyazott
    <modules>/<plugins> szekciókat tartalmaz (NEM pkg_ package -- nincs
    külön al-manifest, minden egy fájlban van).
    """
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"

    _write(
        pkg / "manifest.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3" method="upgrade">
    <name>OneAll Social Login</name>
    <scriptfile>install/script.oneallsociallogin.php</scriptfile>

    <files folder="com_oneallsociallogin">
        <file>index.html</file>
        <file>oneallsociallogin.php</file>
    </files>

    <administration>
        <menu>COM_ONEALLSOCIALLOGIN</menu>
        <files folder="admin">
            <file>controller.php</file>
        </files>
        <languages folder="admin/language">
            <language tag="en-GB">en-GB.com_oneallsociallogin.sys.ini</language>
        </languages>
    </administration>

    <modules>
        <module module="mod_oneallsociallogin" client="site">
            <files folder="mod_oneallsociallogin">
                <file module="mod_oneallsociallogin">mod_oneallsociallogin.php</file>
            </files>
        </module>
    </modules>

    <plugins>
        <plugin plugin="oneallsociallogin" group="system">
            <files folder="plg_oneallsociallogin">
                <file plugin="oneallsociallogin">oneallsociallogin.php</file>
            </files>
        </plugin>
    </plugins>
</extension>
""",
    )
    _write(pkg / "com_oneallsociallogin/index.html", "<html></html>")
    _write(pkg / "com_oneallsociallogin/oneallsociallogin.php", "<?php // component")
    _write(pkg / "admin/controller.php", "<?php // admin controller")
    _write(pkg / "admin/language/en-GB.com_oneallsociallogin.sys.ini", "COM_ONEALLSOCIALLOGIN=OneAll")
    _write(pkg / "mod_oneallsociallogin/mod_oneallsociallogin.php", "<?php // module")
    _write(pkg / "plg_oneallsociallogin/oneallsociallogin.php", "<?php // plugin")

    _run(pkg, out)

    assert (
        out / "components/com_oneallsociallogin/oneallsociallogin.php"
    ).read_text() == "<?php // component"
    assert (
        out / "administrator/components/com_oneallsociallogin/controller.php"
    ).read_text() == "<?php // admin controller"
    assert (
        out / "administrator/language/en-GB/en-GB.com_oneallsociallogin.sys.ini"
    ).read_text() == "COM_ONEALLSOCIALLOGIN=OneAll"
    assert (out / "modules/mod_oneallsociallogin/mod_oneallsociallogin.php").read_text() == "<?php // module"
    assert (out / "plugins/system/oneallsociallogin/oneallsociallogin.php").read_text() == "<?php // plugin"


# ---------------------------------------------------------------------------
# module: site files + media
# ---------------------------------------------------------------------------


def test_module_site_and_media(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"

    _write(
        pkg / "mod_hello.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="module" client="site" method="upgrade">
    <name>mod_hello</name>
    <files folder="modfiles">
        <filename module="mod_hello">mod_hello.php</filename>
        <filename>helper.php</filename>
    </files>
    <media destination="mod_hello" folder="modmedia">
        <folder>images</folder>
    </media>
</extension>
""",
    )
    _write(pkg / "modfiles/mod_hello.php", "<?php // module")
    _write(pkg / "modfiles/helper.php", "<?php // helper")
    _write(pkg / "modmedia/images/icon.png", "PNGDATA")

    _run(pkg, out)

    assert (out / "modules/mod_hello/mod_hello.php").read_text() == "<?php // module"
    assert (out / "modules/mod_hello/helper.php").read_text() == "<?php // helper"
    assert (out / "media/mod_hello/images/icon.png").read_text() == "PNGDATA"


def test_module_administrator_client(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"

    _write(
        pkg / "mod_admhello.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="module" client="administrator" method="upgrade">
    <name>mod_admhello</name>
    <files>
        <filename module="mod_admhello">mod_admhello.php</filename>
    </files>
</extension>
""",
    )
    _write(pkg / "mod_admhello.php", "<?php // adm module")

    _run(pkg, out)

    assert (out / "administrator/modules/mod_admhello/mod_admhello.php").read_text() == "<?php // adm module"


# ---------------------------------------------------------------------------
# plugin: group + element (via filename[@plugin])
# ---------------------------------------------------------------------------


def test_plugin_group_and_element(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"

    _write(
        pkg / "plg_hello.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="plugin" group="content" method="upgrade">
    <name>PLG_CONTENT_HELLO</name>
    <files folder="plgfiles">
        <filename plugin="hello">hello.php</filename>
        <folder>language</folder>
    </files>
</extension>
""",
    )
    _write(pkg / "plgfiles/hello.php", "<?php // plugin")
    _write(pkg / "plgfiles/language/en-GB.plg_content_hello.ini", "PLG=Hello")

    _run(pkg, out)

    assert (out / "plugins/content/hello/hello.php").read_text() == "<?php // plugin"
    assert (out / "plugins/content/hello/language/en-GB.plg_content_hello.ini").read_text() == "PLG=Hello"


def test_plugin_element_fallback_from_name(tmp_path: Path) -> None:
    """Ha nincs <filename plugin="...">, a <name> utolsó '_'-tagja adja az elementet."""
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"

    _write(
        pkg / "plg_system_fallback.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="plugin" group="system" method="upgrade">
    <name>PLG_SYSTEM_FALLBACK</name>
    <files>
        <filename>fallback.php</filename>
    </files>
</extension>
""",
    )
    _write(pkg / "fallback.php", "<?php // fallback")

    _run(pkg, out)

    assert (out / "plugins/system/fallback/fallback.php").read_text() == "<?php // fallback"


# ---------------------------------------------------------------------------
# library
# ---------------------------------------------------------------------------


def test_library(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"

    _write(
        pkg / "lib_hello.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="library" method="upgrade">
    <name>hello</name>
    <files folder="libfiles">
        <filename>hello.php</filename>
        <folder>sub</folder>
    </files>
</extension>
""",
    )
    _write(pkg / "libfiles/hello.php", "<?php // lib")
    _write(pkg / "libfiles/sub/util.php", "<?php // util")

    _run(pkg, out)

    assert (out / "libraries/hello/hello.php").read_text() == "<?php // lib"
    assert (out / "libraries/hello/sub/util.php").read_text() == "<?php // util"


# ---------------------------------------------------------------------------
# template
# ---------------------------------------------------------------------------


def test_template(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"

    _write(
        pkg / "tpl_hello.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="template" client="site" method="upgrade">
    <name>hello</name>
    <files folder="tplfiles">
        <filename>index.php</filename>
        <folder>css</folder>
    </files>
</extension>
""",
    )
    _write(pkg / "tplfiles/index.php", "<?php // tpl")
    _write(pkg / "tplfiles/css/style.css", "body{}")

    _run(pkg, out)

    assert (out / "templates/hello/index.php").read_text() == "<?php // tpl"
    assert (out / "templates/hello/css/style.css").read_text() == "body{}"


# ---------------------------------------------------------------------------
# package (pkg_): al-bővítmények rekurzív feldolgozása
# ---------------------------------------------------------------------------


def test_package_with_component_and_plugin_subextensions(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"

    _write(
        pkg / "pkg_hello.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="package" method="upgrade">
    <name>pkg_hello</name>
    <files folder="packages">
        <file type="component" id="com_hello">com_hello</file>
        <file type="plugin" id="plg_hello">plg_hello</file>
    </files>
</extension>
""",
    )

    _write(
        pkg / "packages/com_hello/com_hello.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3.9.0" method="upgrade">
    <name>com_hello</name>
    <files folder="site">
        <filename>helloworld.php</filename>
    </files>
</extension>
""",
    )
    _write(pkg / "packages/com_hello/site/helloworld.php", "<?php // pkg component")

    _write(
        pkg / "packages/plg_hello/plg_hello.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="plugin" group="content" method="upgrade">
    <name>PLG_CONTENT_HELLO</name>
    <files>
        <filename plugin="hello">hello.php</filename>
    </files>
</extension>
""",
    )
    _write(pkg / "packages/plg_hello/hello.php", "<?php // pkg plugin")

    ops = _run(pkg, out)
    assert len(ops) == 2  # a package saga maga nem másol semmit, csak delegál

    assert (out / "components/com_hello/helloworld.php").read_text() == "<?php // pkg component"
    assert (out / "plugins/content/hello/hello.php").read_text() == "<?php // pkg plugin"


# ---------------------------------------------------------------------------
# hibaesetek
# ---------------------------------------------------------------------------


def test_missing_manifest_raises(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    pkg.mkdir()
    with pytest.raises(jmap.JoomlaManifestError, match="nem található"):
        jmap.find_manifest(pkg)


def test_multiple_manifests_raises(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    _write(pkg / "a.xml", '<extension type="component"><name>com_a</name></extension>')
    _write(pkg / "b.xml", '<extension type="component"><name>com_b</name></extension>')
    with pytest.raises(jmap.JoomlaManifestError, match="több lehetséges manifest"):
        jmap.find_manifest(pkg)


def test_unsupported_extension_type_raises(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"
    _write(pkg / "weird.xml", '<extension type="weird"><name>x</name></extension>')
    manifest_path = jmap.find_manifest(pkg)
    with pytest.raises(jmap.JoomlaManifestError, match="nem támogatott extension type"):
        jmap.build_operations(manifest_path, out)


def test_missing_source_file_raises(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"
    _write(
        pkg / "com_broken.xml",
        """<extension type="component">
    <name>com_broken</name>
    <files>
        <filename>missing.php</filename>
    </files>
</extension>""",
    )
    manifest_path = jmap.find_manifest(pkg)
    ops = jmap.build_operations(manifest_path, out)
    with pytest.raises(jmap.JoomlaManifestError, match="nem létezik"):
        jmap.execute(ops)


def test_plugin_missing_group_raises(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"
    _write(
        pkg / "plg_nogroup.xml",
        """<extension type="plugin">
    <name>PLG_NOGROUP</name>
    <files><filename plugin="nogroup">nogroup.php</filename></files>
</extension>""",
    )
    manifest_path = jmap.find_manifest(pkg)
    with pytest.raises(jmap.JoomlaManifestError, match="'group'"):
        jmap.build_operations(manifest_path, out)


# ---------------------------------------------------------------------------
# CLI end-to-end (subprocess)
# ---------------------------------------------------------------------------


def test_cli_end_to_end(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    out = tmp_path / "out"

    _write(
        pkg / "com_hello.xml",
        """<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3.9.0" method="upgrade">
    <name>com_hello</name>
    <files>
        <filename>helloworld.php</filename>
    </files>
</extension>
""",
    )
    _write(pkg / "helloworld.php", "<?php // cli")

    # A jmap-modul tényleges fájl-útvonalát az importált modulból vesszük,
    # nem a teszt-fájl mellől -- a build-repóban jmap.py a lib/-ben,
    # test_jmap.py a tests/-ben él, a két fájl NEM ugyanabban a könyvtárban.
    script = Path(jmap.__file__)
    result = subprocess.run(
        [sys.executable, str(script), "--package", str(pkg), "--out", str(out)],
        capture_output=True,
        text=True,
        check=False,
    )

    assert result.returncode == 0, result.stderr
    assert "kész:" in result.stdout
    assert (out / "components/com_hello/helloworld.php").read_text() == "<?php // cli"


def test_cli_reports_error_exit_code(tmp_path: Path) -> None:
    pkg = tmp_path / "empty_pkg"
    pkg.mkdir()
    out = tmp_path / "out"

    # A jmap-modul tényleges fájl-útvonalát az importált modulból vesszük,
    # nem a teszt-fájl mellől -- a build-repóban jmap.py a lib/-ben,
    # test_jmap.py a tests/-ben él, a két fájl NEM ugyanabban a könyvtárban.
    script = Path(jmap.__file__)
    result = subprocess.run(
        [sys.executable, str(script), "--package", str(pkg), "--out", str(out)],
        capture_output=True,
        text=True,
        check=False,
    )

    assert result.returncode == 1
    assert "hiba:" in result.stderr
