#!/usr/bin/env python3
"""Upload Panorama Lab to https://magicphotobooth.gr/lab/"""
from __future__ import annotations

import ssl
from ftplib import FTP_TLS
from io import BytesIO
from pathlib import Path

HOST = "213.158.90.64"
USER = "cursor-prosfores"
PASS = "H3+kbC1yH3+kbC1y"
REMOTE_ROOT = "/magicphotobooth.gr/lab"

ROOT = Path(__file__).resolve().parent
PUBLIC = ROOT / "public"
SKIP_NAMES = {".DS_Store", ".gitignore"}
SKIP_SUFFIXES = {".sqlite", ".log"}

HTACCESS = """\
RewriteEngine On
RewriteBase /lab/

RewriteRule ^(?:src|views|data|windows|dist)(?:/|$) - [F,L]
RewriteRule ^(?:bootstrap|config)\\.php$ - [F,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
"""


class ReusedFTPS(FTP_TLS):
    def ntransfercmd(self, cmd, rest=None):
        conn, size = super(FTP_TLS, self).ntransfercmd(cmd, rest)
        if self._prot_p:
            conn = self.context.wrap_socket(
                conn,
                server_hostname=self.host,
                session=self.sock.session,
            )
        return conn, size


def connect() -> FTP_TLS:
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    ftp = ReusedFTPS(context=ctx)
    ftp.connect(HOST, 21, timeout=600)
    ftp.auth()
    ftp.login(USER, PASS)
    ftp.prot_p()
    ftp.set_pasv(True)
    return ftp


def ensure_dir(ftp: FTP_TLS, path: str) -> None:
    ftp.cwd("/")
    for part in path.strip("/").split("/"):
        try:
            ftp.cwd(part)
        except Exception:
            ftp.mkd(part)
            ftp.cwd(part)


def upload_file(ftp: FTP_TLS, local: Path, remote: str) -> None:
    remote = remote.lstrip("/")
    parts = remote.split("/")
    ensure_dir(ftp, "/".join(parts[:-1]))
    with local.open("rb") as fh:
        ftp.storbinary(f"STOR {parts[-1]}", fh)
    print(f"UPLOADED /{remote}")


def upload_bytes(ftp: FTP_TLS, data: bytes, remote: str) -> None:
    remote = remote.lstrip("/")
    parts = remote.split("/")
    ensure_dir(ftp, "/".join(parts[:-1]))
    ftp.storbinary(f"STOR {parts[-1]}", BytesIO(data))
    print(f"UPLOADED /{remote} (generated)")


def chmod(ftp: FTP_TLS, path: str, mode: str) -> None:
    try:
        ftp.voidcmd(f"SITE CHMOD {mode} {path}")
        print(f"CHMOD {mode} {path}")
    except Exception as e:
        print(f"CHMOD skip {path}: {e}")


def walk_upload(ftp: FTP_TLS, local_dir: Path, remote_dir: str) -> None:
    for path in sorted(local_dir.rglob("*")):
        if path.name in SKIP_NAMES or path.suffix in SKIP_SUFFIXES:
            continue
        if path.is_dir():
            continue
        rel = path.relative_to(local_dir).as_posix()
        upload_file(ftp, path, f"{remote_dir}/{rel}")


def pick_root(ftp: FTP_TLS) -> str:
    names = []
    ftp.cwd("/")
    ftp.retrlines("NLST", names.append)
    print("FTP root:", names)
    for candidate in (
        "/magicphotobooth.gr/lab",
        "/httpdocs/lab",
        "/lab",
    ):
        ftp.cwd("/")
        ok = True
        for part in candidate.strip("/").split("/")[:-1]:
            try:
                ftp.cwd(part)
            except Exception:
                ok = False
                break
        if ok:
            return candidate
    return REMOTE_ROOT


def main() -> int:
    ftp = connect()
    print("Connected", ftp.pwd())
    remote = pick_root(ftp)
    print("Remote", remote)
    ensure_dir(ftp, remote)
    for sub in ("data/uploads", "data/orders", "data/hotfolder", "update", "assets/art", "download"):
        ensure_dir(ftp, f"{remote}/{sub}")

    walk_upload(ftp, PUBLIC, remote)
    upload_bytes(ftp, HTACCESS.encode("utf-8"), f"{remote}/.htaccess")
    upload_file(ftp, ROOT / "bootstrap.php", f"{remote}/bootstrap.php")
    upload_file(ftp, ROOT / "config.php", f"{remote}/config.php")
    upload_file(ftp, ROOT / "VERSION", f"{remote}/VERSION")
    if (ROOT / "CHANGELOG.md").is_file():
        upload_file(ftp, ROOT / "CHANGELOG.md", f"{remote}/CHANGELOG.md")
    walk_upload(ftp, ROOT / "src", f"{remote}/src")
    walk_upload(ftp, ROOT / "views", f"{remote}/views")
    upload_file(ftp, ROOT / "data/.htaccess", f"{remote}/data/.htaccess")

    update_dir = ROOT / "dist" / "update"
    if update_dir.is_dir():
        for name in ("latest.json", "PanoramaLab-app.zip", "PanoramaLab.exe"):
            local = update_dir / name
            if local.is_file():
                upload_file(ftp, local, f"{remote}/update/{name}")

    setup = ROOT / "dist" / "PanoramaLab-Setup.exe"
    if setup.is_file():
        upload_file(ftp, setup, f"{remote}/download/PanoramaLab-Setup.exe")
    winzip = ROOT / "dist" / "PanoramaLab-Windows.zip"
    if winzip.is_file():
        upload_file(ftp, winzip, f"{remote}/download/PanoramaLab-Windows.zip")
    maczip = ROOT / "dist" / "PanoramaLab-Mac.zip"
    if maczip.is_file():
        upload_file(ftp, maczip, f"{remote}/download/PanoramaLab-Mac.zip")

    chmod(ftp, f"{remote}/data", "0777")
    chmod(ftp, f"{remote}/data/uploads", "0777")
    chmod(ftp, f"{remote}/data/orders", "0777")
    chmod(ftp, f"{remote}/data/hotfolder", "0777")
    chmod(ftp, f"{remote}/data/print-ready", "0777")
    chmod(ftp, f"{remote}/data/lab.sqlite", "0666")
    chmod(ftp, f"{remote}/data/lab.sqlite-wal", "0666")
    chmod(ftp, f"{remote}/data/lab.sqlite-shm", "0666")
    chmod(ftp, f"{remote}/data/lab.sqlite-journal", "0666")

    ftp.quit()
    print("Done. https://magicphotobooth.gr/lab/")
    return 0


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