#!/usr/bin/env python3
"""GUARDiA CI/CD Webhook 서버 (포트 9999) — 6개 repo 지원"""
import http.server, subprocess, threading, json, hmac, hashlib, logging
import os, urllib.request, base64

SECRET        = b"zioinfo-deploy-2026"
LOG           = "/var/log/zioinfo/deploy.log"
JENKINS_URL   = "http://127.0.0.1:9080"
JENKINS_USER  = "admin"
JENKINS_TOKEN = "Admin@2026!"
ITSM_NOTIFY   = "http://127.0.0.1:9001/api/messenger/webhook"

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(message)s",
    handlers=[logging.FileHandler(LOG), logging.StreamHandler()])


def notify_itsm(success: bool, msg: str):
    try:
        body = json.dumps({"event": "build_result", "room": "ops",
                           "success": success, "result_summary": msg}).encode()
        req = urllib.request.Request(
            ITSM_NOTIFY, data=body,
            headers={"Content-Type": "application/json"})
        urllib.request.urlopen(req, timeout=5)
    except Exception:
        pass


def trigger_jenkins(job: str):
    try:
        cred = base64.b64encode(f"{JENKINS_USER}:{JENKINS_TOKEN}".encode()).decode()
        headers = {"Authorization": f"Basic {cred}"}
        crumb_req = urllib.request.Request(
            f"{JENKINS_URL}/crumbIssuer/api/json", headers=headers)
        crumb_data = json.loads(urllib.request.urlopen(crumb_req, timeout=5).read())
        headers[crumb_data["crumbRequestField"]] = crumb_data["crumb"]
        build_req = urllib.request.Request(
            f"{JENKINS_URL}/job/{job}/build?token=gitea-build-2026",
            data=b"", headers=headers)
        urllib.request.urlopen(build_req, timeout=5)
    except Exception:
        pass


def run_steps(repo: str, steps: list) -> bool:
    for name, cmd in steps:
        logging.info(f"[{repo}:{name}] 실행 중...")
        try:
            result = subprocess.run(
                cmd, capture_output=True, text=True, timeout=300)
            if result.stdout.strip():
                logging.info(f"[{repo}:{name}] 완료")
            if result.returncode != 0:
                logging.error(f"[{repo}:{name}] 실패: {(result.stdout + result.stderr)[:200]}")
                return False
            else:
                logging.info(f"[{repo}:{name}] 완료")
        except Exception as e:
            logging.error(f"[{repo}:{name}] 예외: {e}")
            return False
    return True


class WebhookHandler(http.server.BaseHTTPRequestHandler):
    def do_POST(self):
        try:
            length = int(self.headers.get("Content-Length", 0))
            body = self.rfile.read(length) if length else b""
            sig = self.headers.get("X-Gitea-Signature", "")
            if sig:
                expected = hmac.new(SECRET, body, hashlib.sha256).hexdigest()
                if not hmac.compare_digest(sig, expected):
                    self.send_response(403); self.end_headers(); return
        except Exception:
            body = b""

        self.send_response(202)
        self.end_headers()
        self.wfile.write(b"Deploy queued")

        try:
            payload = json.loads(body) if body else {}
        except Exception:
            payload = {}

        repo = payload.get("repository", {}).get("name", "")
        branch = payload.get("ref", "").replace("refs/heads/", "")
        logging.info(f"Webhook 수신: repo={repo} branch={branch}")

        if not repo:
            return

        threading.Thread(target=self._deploy, args=(repo,), daemon=True).start()

    def _deploy(self, repo: str):
        logging.info(f"=== {repo} 배포 시작 ===")

        if repo == "zioinfo-web":
            SRC = "/opt/zioinfo/src"
            ok = run_steps(repo, [
                ("git pull",     ["bash", "-c",
                    f"[ -d {SRC}/.git ] && git -C {SRC} fetch origin main && git -C {SRC} reset --hard origin/main"
                    f" || git clone 'http://zio:Zio%40Admin2026%21@127.0.0.1:9003/zio/zioinfo-web.git' {SRC}"]),
                ("npm build",    ["bash", "-c",
                    f"cd {SRC}/frontend && npm ci --legacy-peer-deps 2>/dev/null || npm install --legacy-peer-deps && npm run build"]),
                ("copy to www",  ["bash", "-c",
                    f"cp -r {SRC}/backend/src/main/resources/static/. /var/www/zioinfo/ && echo 'copied'"]),
                ("mvn package",  ["bash", "-c",
                    f"cd {SRC}/backend && /usr/bin/mvn clean package -DskipTests -q"]),
                ("deploy jar",   ["bash", "-c",
                    f"cp {SRC}/backend/target/zioinfo-web-*.jar /opt/zioinfo/app/app.jar"]),
                ("restart",      ["systemctl", "restart", "zioinfo"]),
                ("health check", ["bash", "-c", "sleep 5 && systemctl is-active zioinfo"]),
            ])
            if ok:
                notify_itsm(True,  "✅ zioinfo-web 배포 완료")
                trigger_jenkins("zioinfo-web")
            else:
                notify_itsm(False, "❌ zioinfo-web 빌드 실패")

        elif repo == "guardia-itsm":
            SRC = "/opt/guardia/src"
            ok = run_steps(repo, [
                ("git pull",     ["bash", "-c",
                    f"[ -d {SRC}/.git ] && git -C {SRC} fetch origin main && git -C {SRC} reset --hard origin/main"
                    f" || git clone 'http://zio:Zio%40Admin2026%21@127.0.0.1:9003/zio/guardia-itsm.git' {SRC}"]),
                ("rsync",        ["bash", "-c",
                    f"rsync -a --exclude=__pycache__ --exclude=.git "
                    f"--exclude=rpa_rules.json --exclude='*.pyc' "
                    f"{SRC}/ /opt/guardia/app/"]),
                ("pip install",  ["bash", "-c",
                    "/opt/guardia/venv/bin/pip install -r /opt/guardia/app/requirements.txt -q"]),
                ("restart",      ["systemctl", "restart", "guardia"]),
                ("health check", ["bash", "-c", "sleep 4 && systemctl is-active guardia"]),
            ])
            if ok:
                notify_itsm(True,  "✅ guardia-itsm 배포 완료")
                trigger_jenkins("guardia-itsm")
            else:
                notify_itsm(False, "❌ guardia-itsm 빌드 실패")

        elif repo == "guardia-manager":
            SRC = "/opt/manager/src"
            ok = run_steps(repo, [
                ("git pull",     ["bash", "-c",
                    f"[ -d {SRC}/.git ] && git -C {SRC} fetch origin main && git -C {SRC} reset --hard origin/main"
                    f" || git clone 'http://zio:Zio%40Admin2026%21@127.0.0.1:9003/zio/guardia-manager.git' {SRC}"]),
                ("npm build",    ["bash", "-c",
                    f"cd {SRC}/frontend && npm ci 2>/dev/null || npm install && npm run build"]),
                ("copy dist",    ["bash", "-c",
                    f"cp -r {SRC}/frontend/dist/. /var/www/manager/ 2>/dev/null || "
                    f"cp -r {SRC}/dist/. /var/www/manager/"]),
                ("restart",      ["systemctl", "restart", "guardia-manager", "2>/dev/null", "||", "true"]),
            ])
            if ok:
                notify_itsm(True,  "✅ guardia-manager 배포 완료")
                trigger_jenkins("guardia-manager")
            else:
                notify_itsm(False, "❌ guardia-manager 빌드 실패")

        elif repo == "guardia-docs":
            SRC = "/opt/guardia-docs/src"
            ok = run_steps(repo, [
                ("git pull",  ["bash", "-c",
                    f"[ -d {SRC}/.git ] && git -C {SRC} fetch origin main && git -C {SRC} reset --hard origin/main"
                    f" || git clone 'http://zio:Zio%40Admin2026%21@127.0.0.1:9003/zio/guardia-docs.git' {SRC}"]),
                ("copy docs", ["bash", "-c",
                    f"mkdir -p /var/www/docs && rsync -a --delete {SRC}/ /var/www/docs/"]),
            ])
            if ok:
                notify_itsm(True, "✅ guardia-docs 배포 완료")
            else:
                notify_itsm(False, "❌ guardia-docs 빌드 실패")

        elif repo == "guardia-messenger":
            trigger_jenkins("guardia-messenger")

        elif repo == "zioinfo-mail":
            SRC = "/opt/mail"
            ok = run_steps(repo, [
                ("git pull",     ["bash", "-c",
                    f"[ -d {SRC}/src/.git ] && git -C {SRC}/src fetch origin main && git -C {SRC}/src reset --hard origin/main"
                    f" || git clone 'http://zio:Zio%40Admin2026%21@127.0.0.1:9003/zio/zioinfo-mail.git' {SRC}/src"]),
                ("npm build",    ["bash", "-c",
                    f"cd {SRC}/src/frontend && npm ci --legacy-peer-deps 2>/dev/null || npm install --legacy-peer-deps && npm run build"]),
                ("copy dist",    ["bash", "-c",
                    f"mkdir -p /var/www/mail && cp -r {SRC}/src/dist/. /var/www/mail/"]),
                ("pip install",  ["bash", "-c",
                    f"{SRC}/venv/bin/pip install -r {SRC}/src/backend/requirements.txt -q"]),
                ("rsync",        ["bash", "-c",
                    f"rsync -a --exclude=__pycache__ --exclude=.git --exclude='*.pyc' --exclude='.env' {SRC}/src/backend/ {SRC}/backend/"]),
                ("restart",      ["systemctl", "restart", "zioinfo-mail"]),
                ("health check", ["bash", "-c", "sleep 4 && curl -sf http://localhost:8026/health"]),
            ])
            if ok:
                notify_itsm(True,  "✅ zioinfo-mail 배포 완료")
                trigger_jenkins("zioinfo-mail")
            else:
                notify_itsm(False, "❌ zioinfo-mail 빌드 실패")

        logging.info(f"=== {repo} 배포 완료 ===")

    def log_message(self, fmt, *args):
        logging.info(fmt % args)


if __name__ == "__main__":
    os.makedirs("/var/log/zioinfo", exist_ok=True)
    logging.info("GUARDiA CI/CD Webhook 서버 시작 (포트 9999) — 6개 repo 지원")
    server = http.server.HTTPServer(("0.0.0.0", 9999), WebhookHandler)
    server.serve_forever()
