# build_release.py
"""
Automatizace build/export/aktualizace Kodi addonu:
- Zvýšení verze v addon.xml (MAJOR.X.Y: Y 0–9, při přetečení Y → X+1, Y=0)
- Vložení novinek z news.txt do <news> v addon.xml
- Zabalení pouze potřebných souborů do ZIP
- Upload ZIP na FTP
 - Upload libovolného souboru na FTP a generování addons.xml + MD5.
"""
import os
import re
import shutil
import xml.etree.ElementTree as ET
from zipfile import ZipFile, ZIP_DEFLATED
from ftplib import FTP
import hashlib

# === KONFIGURACE ===
FTP_HOST = "repo.ido.cz"
FTP_PORT = 21
FTP_USER = "mirahoresrepo"
FTP_PASS = "bovh#DPF29"
FTP_ROOT = "/web/zips/plugin.video.mmirousek/"
ADDON_XML = os.path.join(r"c:\Users\mmiro\AppData\Roaming\Kodi\addons\plugin.video.mmirousek_v3", "addon.xml")
NEWS_TXT = os.path.join(r"c:\Users\mmiro\AppData\Roaming\Kodi\addons\plugin.video.mmirousek_v3", "news.txt")

# Cesta ke složce addonu (hardcoded)
ADDON_PATH = r"c:\Users\mmiro\AppData\Roaming\Kodi\addons\plugin.video.mmirousek_v3"
ADDON_DIR = "plugin.video.mmirousek_v3"

# True = nahrát build na FTP; False = jen uložit ZIP a addons.xml do LOCAL_BUILD_DIR
UPLOAD_TO_FTP = True
# Při UPLOAD_TO_FTP=False: cílová složka (ZIP, addons.xml, addons.xml.md5, případně repo ZIP)
LOCAL_BUILD_DIR = os.path.join(ADDON_PATH, "release_build")

# Volitelně vytvořit/upload repository ZIP (nastavte True pokud chcete generovat repo ZIP)
GENERATE_REPO_ZIP = False
# ID repository addonu
REPO_ID = "repository.mmirahoresrepo"
# Pokud None, použije se bumpovaná verze `new_version`. Jinak zadejte explicitně, např. "3.0.2"
REPO_ZIP_VERSION = None

# Soubory/složky, které NECHCEME v ZIPu
EXCLUDE = [
    ".git", "__pycache__", ".DS_Store", "*.md", "*.yml", "*.bat", "*.sh", "test", "tests", "*.pyc", "*.zip", "*.jpg", "*.jpeg", "*.json", "web",
]

# === FUNKCE ===
def get_current_version(xml_path):
    tree = ET.parse(xml_path)
    root = tree.getroot()
    return root.attrib["version"]

def bump_version(version):
    """
    Zvýší verzi MAJOR.X.Y: poslední segment +1; pokud Y > 9, přenos do X (Y -= 10).
    Např. 3.0.9 → 3.1.0; ze starší 3.0.13 → 3.1.4 (jeden krok = +1 s normalizací).
    """
    parts = version.split(".")
    if len(parts) != 3:
        raise ValueError(
            "Verze musí mít přesně 3 části MAJOR.X.Y, např. 3.1.4; dostal jsem: %r"
            % (version,)
        )
    major, x, y = int(parts[0]), int(parts[1]), int(parts[2])
    y += 1
    while y > 9:
        y -= 10
        x += 1
    return "%d.%d.%d" % (major, x, y)

def update_version_in_xml(xml_path, new_version):
    tree = ET.parse(xml_path)
    root = tree.getroot()
    root.attrib["version"] = new_version
    tree.write(xml_path, encoding="utf-8", xml_declaration=True)

def update_news_in_xml(xml_path, news_path):
    tree = ET.parse(xml_path)
    root = tree.getroot()
    
    # 1. Najdeme správný extension tag (metadata)
    metadata_ext = None
    for ext in root.findall('extension'):
        if ext.get('point') == 'xbmc.addon.metadata':
            metadata_ext = ext
            break
            
    if metadata_ext is not None:
        # 2. Hledáme <news> uvnitř metadat, nikoliv v rootu
        news_elem = metadata_ext.find("news")
        
        # 3. Pokud tam <news> není, vytvoříme ho jako podřízený prvek metadat
        if news_elem is None:
            news_elem = ET.SubElement(metadata_ext, "news")
            
        # 4. Vložíme text ze souboru
        with open(news_path, encoding="utf-8") as f:
            news_elem.text = f.read()
    else:
        print("UPOZORNĚNÍ: V addon.xml nebyla nalezena sekce xbmc.addon.metadata!")

    tree.write(xml_path, encoding="utf-8", xml_declaration=True)
def upload_file_ftp(local_path, remote_name=None, subfolder=None):
    """Upload souboru na FTP s rekurzivním vytvořením podsložek."""
    if remote_name is None:
        remote_name = os.path.basename(local_path)
    with FTP() as ftp:
        ftp.connect(FTP_HOST, FTP_PORT)
        ftp.login(FTP_USER, FTP_PASS)
        ftp.cwd(FTP_ROOT)

        if subfolder:
            # Rekurzivní vytvoření složek
            folders = subfolder.replace("\\", "/").split("/")
            for folder in folders:
                if not folder:
                    continue
                try:
                    ftp.cwd(folder)
                except Exception:
                    ftp.mkd(folder)
                    ftp.cwd(folder)

        with open(local_path, "rb") as f:
            ftp.storbinary(f"STOR {remote_name}", f)

    slozka_info = subfolder if subfolder else "root"
    print(f"Upload na FTP hotov: {remote_name} -> složka: {slozka_info}")

def generate_repo_xml_and_md5(addon_xml_path, out_xml_path, out_md5_path):
    """Vytvoří jednoduchý repository XML se <addons> root obsahující tento addon a vygeneruje MD5 soubor."""
    tree = ET.parse(addon_xml_path)
    addon_elem = tree.getroot()
    addons_root = ET.Element("addons")
    addons_root.append(addon_elem)
    addons_tree = ET.ElementTree(addons_root)
    addons_tree.write(out_xml_path, encoding="utf-8", xml_declaration=True)

    # Compute md5
    hash_md5 = hashlib.md5()
    with open(out_xml_path, "rb") as f:
        for chunk in iter(lambda: f.read(8192), b""):
            hash_md5.update(chunk)
    md5sum = hash_md5.hexdigest()
    with open(out_md5_path, "w", encoding="utf-8") as f:
        f.write(md5sum)
    print(f"Vygenerováno {out_xml_path} a {out_md5_path}")


import fnmatch
import tempfile


def should_include(path):
    for pattern in EXCLUDE:
        if fnmatch.fnmatch(os.path.basename(path), pattern):
            return False
    return True


def zip_addon(zip_path, addon_path, addon_dir):
    with ZipFile(zip_path, "w", ZIP_DEFLATED) as zipf:
        for root, dirs, files in os.walk(addon_path):
            # Exclude dirs
            dirs[:] = [d for d in dirs if should_include(d)]
            for file in files:
                if should_include(file):
                    abs_path = os.path.join(root, file)
                    rel_path = os.path.relpath(abs_path, addon_path)
                    zipf.write(abs_path, os.path.join(addon_dir, rel_path))


def copy_build_to_local_folder(zip_path, local_addons, local_md5, dest_dir):
    """Zkopíruje ZIP addonu a addons.xml + MD5 do lokální složky (bez FTP)."""
    os.makedirs(dest_dir, exist_ok=True)
    shutil.copy2(zip_path, os.path.join(dest_dir, os.path.basename(zip_path)))
    shutil.copy2(local_addons, os.path.join(dest_dir, "addons.xml"))
    shutil.copy2(local_md5, os.path.join(dest_dir, "addons.xml.md5"))
    print(f"Výstup uložen do: {dest_dir}")


def main():
    print("--- Build & Release Kodi Addon ---")
    # 1. Zjisti a zvedni verzi
    old_version = get_current_version(ADDON_XML)
    new_version = bump_version(old_version)
    update_version_in_xml(ADDON_XML, new_version)
    print(f"Verze zvýšena: {old_version} -> {new_version}")
    # 2. Vlož novinky
    update_news_in_xml(ADDON_XML, NEWS_TXT)
    print(f"Novinky vloženy z {NEWS_TXT}")
    # 3. Zabal addon
    zip_name = f"{ADDON_DIR}-{new_version}.zip"
    zip_addon(zip_name, ADDON_PATH, ADDON_DIR)
    print(f"Addon zabalen do {zip_name}")
    # 4. Vygenerovat repository XML (addons.xml) a MD5 (vždy lokálně v ADDON_PATH)
    local_addons = os.path.join(ADDON_PATH, "addons.xml")
    local_md5 = os.path.join(ADDON_PATH, "addons.xml.md5")
    generate_repo_xml_and_md5(ADDON_XML, local_addons, local_md5)
    # 5. FTP upload nebo uložení do složky
    possible_icons = [
        os.path.join(ADDON_PATH, "icon.png"),
        os.path.join(ADDON_PATH, "fanart.jpg"),
        os.path.join(ADDON_PATH, "resources", "icon.png"),
        os.path.join(ADDON_PATH, "resources", "media", "fanart.jpg"),
    ]
    if UPLOAD_TO_FTP:
        upload_file_ftp(zip_name, subfolder=ADDON_DIR)
        upload_file_ftp(local_addons)
        upload_file_ftp(local_md5)
        for p in possible_icons:
            if os.path.exists(p):
                rel_dir = os.path.dirname(os.path.relpath(p, ADDON_PATH))
                target_subfolder = ADDON_DIR
                if rel_dir:
                    target_subfolder = f"{ADDON_DIR}/{rel_dir.replace(chr(92), '/')}"
                upload_file_ftp(p, subfolder=target_subfolder)
    else:
        print("Přeskakuji upload na FTP (UPLOAD_TO_FTP=False).")
        copy_build_to_local_folder(zip_name, local_addons, local_md5, LOCAL_BUILD_DIR)
    # 6. (Volitelně) Vytvořit a nahrát repository ZIP (pro instalaci repozitáře v Kodi)
    if GENERATE_REPO_ZIP:
        repo_id = REPO_ID
        repo_version = REPO_ZIP_VERSION or new_version
        repo_zip_name = f"{repo_id}-{repo_version}.zip"
        try:
            tmpdir = tempfile.mkdtemp()
            repo_folder = os.path.join(tmpdir, repo_id)
            os.makedirs(repo_folder, exist_ok=True)
            # vytvořit addon.xml pro repository addon (správný extension point a dir)
            repo_addon_xml = f'''<?xml version="1.0" encoding="UTF-8"?>
<addon id="{repo_id}" name="Mmirahores Repository" version="{repo_version}" provider-name="mirahores">
    <extension point="xbmc.addon.repository" name="Mmirahores Repository">
        <dir>
            <info compressed="false">https://repo.ido.cz/zips/plugin.video.mmirousek/addons.xml</info>
            <checksum>https://repo.ido.cz/zips/plugin.video.mmirousek/addons.xml.md5</checksum>
            <datadir zip="true">https://repo.ido.cz/zips/plugin.video.mmirousek/</datadir>
        </dir>
    </extension>
    <extension point="xbmc.addon.metadata">
        <summary>Repository for Mmirahores addons</summary>
        <description>Oficiální repozitář pro doplněk mmirousek.</description>
        <platform>all</platform>
        <assets>
            <icon>icon.png</icon>
        </assets>
    </extension>
</addon>
'''
            with open(os.path.join(repo_folder, "addon.xml"), "w", encoding="utf-8") as f:
                f.write(repo_addon_xml)
            # zkopírovat addons.xml a md5 do repo folderu
            shutil.copy(local_addons, os.path.join(repo_folder, "addons.xml"))
            shutil.copy(local_md5, os.path.join(repo_folder, "addons.xml.md5"))
            # kopírovat ikony pokud existují
            for p in possible_icons:
                if os.path.exists(p):
                    shutil.copy(p, os.path.join(repo_folder, os.path.basename(p)))
            # vytvořit zip
            repo_zip_path = os.path.join(os.getcwd(), repo_zip_name)
            # Create zip with files at root (no top-level folder)
            with ZipFile(repo_zip_path, "w", ZIP_DEFLATED) as zipf:
                for root, dirs, files in os.walk(repo_folder):
                    for file in files:
                        abs_path = os.path.join(root, file)
                        rel_path = os.path.relpath(abs_path, repo_folder)
                        # put files under top-level folder <repo_id>/ inside the zip
                        rel_path = os.path.join(repo_id, rel_path)
                        zipf.write(abs_path, rel_path)
            if UPLOAD_TO_FTP:
                upload_file_ftp(repo_zip_path, subfolder=repo_id)
                print(f"Repository ZIP vygenerován a nahrán: {repo_zip_name}")
            else:
                os.makedirs(LOCAL_BUILD_DIR, exist_ok=True)
                shutil.copy2(repo_zip_path, os.path.join(LOCAL_BUILD_DIR, repo_zip_name))
                print(f"Repository ZIP vygenerován a uložen do {LOCAL_BUILD_DIR}: {repo_zip_name}")
        finally:
            try:
                shutil.rmtree(tmpdir)
            except Exception:
                pass
    else:
        print("Přeskakuji generování repository ZIP (GENERATE_REPO_ZIP=False).")
    print("Hotovo!")

if __name__ == "__main__":
    main()
