#!/usr/bin/env python3
"""
Restores a bundle produced by golder_db_bundle_export.py.

Requirements on the VPS:
  - Python 3.9+
  - mysql binary available in PATH
  - A MySQL admin user with CREATE DATABASE / CREATE USER / GRANT privileges

Example:
  python tools/golder_db_bundle_restore.py \
    --bundle backups/golder_backup_20260318_214500.zip \
    --host 127.0.0.1 \
    --port 3306 \
    --admin-user root \
    --admin-pass 'ROOT-SIFRE'
"""

from __future__ import annotations

import argparse
import json
import os
import shutil
import subprocess
import sys
import tempfile
import zipfile
from pathlib import Path

import mysql.connector


def require_binary(binary_name: str) -> None:
    if shutil.which(binary_name):
        return
    print(f"HATA: '{binary_name}' PATH icinde bulunamadi.", file=sys.stderr)
    sys.exit(1)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Golder backup bundle dosyasindan master ve tenant DB'leri geri yukler."
    )
    parser.add_argument("--bundle", required=True)
    parser.add_argument("--host", default="127.0.0.1")
    parser.add_argument("--port", type=int, default=3306)
    parser.add_argument("--admin-user", required=True)
    parser.add_argument("--admin-pass", required=True)
    return parser.parse_args()


def run_mysql_file(
    host: str,
    port: int,
    user: str,
    password: str,
    sql_file: Path,
) -> None:
    env = os.environ.copy()
    env["MYSQL_PWD"] = password
    cmd = [
        "mysql",
        f"--host={host}",
        f"--port={port}",
        f"--user={user}",
        "--default-character-set=utf8mb4",
    ]
    with sql_file.open("rb") as handle:
        result = subprocess.run(
            cmd,
            env=env,
            stdin=handle,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            check=False,
        )
    if result.returncode != 0:
        stderr = result.stderr.decode("utf-8", errors="replace").strip()
        raise RuntimeError(f"{sql_file.name} import edilemedi: {stderr}")


def ensure_tenant_user(
    connection: mysql.connector.MySQLConnection,
    host_pattern: str,
    db_name: str,
    db_user: str,
    db_pass: str,
) -> None:
    safe_db_name = db_name.replace("`", "``")
    safe_db_user = db_user.replace("'", "''")
    safe_db_pass = db_pass.replace("'", "''")
    safe_host = host_pattern.replace("'", "''")

    statements = [
        (
            f"CREATE USER IF NOT EXISTS '{safe_db_user}'@'{safe_host}' "
            f"IDENTIFIED BY '{safe_db_pass}'"
        ),
        (
            f"ALTER USER '{safe_db_user}'@'{safe_host}' "
            f"IDENTIFIED BY '{safe_db_pass}'"
        ),
        (
            f"GRANT ALL PRIVILEGES ON `{safe_db_name}`.* "
            f"TO '{safe_db_user}'@'{safe_host}'"
        ),
    ]
    cursor = connection.cursor()
    try:
        for statement in statements:
            cursor.execute(statement)
        connection.commit()
    finally:
        cursor.close()


def main() -> int:
    args = parse_args()
    require_binary("mysql")

    bundle_path = Path(args.bundle).resolve()
    if not bundle_path.exists():
        print(f"HATA: bundle bulunamadi: {bundle_path}", file=sys.stderr)
        return 1

    with tempfile.TemporaryDirectory(prefix="golder_restore_") as temp_dir:
        temp_path = Path(temp_dir)
        with zipfile.ZipFile(bundle_path, "r") as zf:
            zf.extractall(temp_path)

        manifest_path = temp_path / "manifest.json"
        if not manifest_path.exists():
            print("HATA: manifest.json bundle icinde yok.", file=sys.stderr)
            return 1

        manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
        master_db = manifest["master_db"]
        tenant_list = manifest.get("tenants", [])

        connection = mysql.connector.connect(
            host=args.host,
            port=args.port,
            user=args.admin_user,
            password=args.admin_pass,
        )
        try:
            print(f"Master veritabani import ediliyor: {master_db}")
            master_sql = temp_path / "dumps" / f"{master_db}.sql"
            run_mysql_file(
                host=args.host,
                port=args.port,
                user=args.admin_user,
                password=args.admin_pass,
                sql_file=master_sql,
            )

            for index, tenant in enumerate(tenant_list, start=1):
                db_name = tenant["mysql_db_name"]
                db_user = tenant["mysql_db_user"]
                db_pass = tenant["mysql_db_pass"]

                print(
                    f"[{index}/{len(tenant_list)}] Kullanici ve yetki ayarlaniyor: "
                    f"{db_user} -> {db_name}"
                )
                ensure_tenant_user(
                    connection=connection,
                    host_pattern="%",
                    db_name=db_name,
                    db_user=db_user,
                    db_pass=db_pass,
                )

                tenant_sql = temp_path / "dumps" / f"{db_name}.sql"
                print(f"[{index}/{len(tenant_list)}] Tenant import ediliyor: {db_name}")
                run_mysql_file(
                    host=args.host,
                    port=args.port,
                    user=args.admin_user,
                    password=args.admin_pass,
                    sql_file=tenant_sql,
                )

            cursor = connection.cursor()
            try:
                cursor.execute("FLUSH PRIVILEGES")
                connection.commit()
            finally:
                cursor.close()
        finally:
            connection.close()

    print("Tum veritabanlari geri yuklendi.")
    return 0


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