from __future__ import annotations

import argparse
import io
import os
import sys
import uuid
from pathlib import Path
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen

import boto3
import mysql.connector
from botocore.config import Config
from botocore.exceptions import ClientError
from PIL import Image, ImageOps


ROOT_DIR = Path(__file__).resolve().parents[1]
DEFAULT_ENV_PATH = ROOT_DIR / ".env"

NCP_ACCESS_KEY = "ncp_iam_BPASKR5aqRFd5UVurpnn"
NCP_SECRET_KEY = "ncp_iam_BPKSKR33fSB43WgsitoAeirg4QGRNecX5p"
NCP_BUCKET_NAME = "babynote"
NCP_ENDPOINT = "https://kr.object.ncloudstorage.com"
CDN_DOMAIN = "https://uscppbpkqffl28953595.gcdn.ntruss.com"


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Backfill image_path by uploading current image_url to NCP.")
    parser.add_argument("--type-names", nargs="+", required=True, help="Korean type_name values to backfill")
    parser.add_argument("--dry-run", action="store_true")
    return parser.parse_args()


def load_env(env_path: str) -> None:
    path = Path(env_path)
    if not path.exists():
        return
    for line in path.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#") or "=" not in line:
            continue
        key, value = line.split("=", 1)
        os.environ.setdefault(key.strip(), value.strip())


def create_db_connection():
    return mysql.connector.connect(
        host=os.environ["DB_HOST"],
        port=int(os.environ.get("DB_PORT", "3306")),
        user=os.environ["DB_USER"],
        password=os.environ["DB_PASSWORD"],
        database=os.environ["DB_NAME"],
        charset="utf8mb4",
    )


def create_s3_client():
    session = boto3.session.Session()
    cfg = Config(signature_version="s3", s3={"addressing_style": "path"})
    return session.client(
        "s3",
        region_name="kr-standard",
        endpoint_url=NCP_ENDPOINT,
        aws_access_key_id=NCP_ACCESS_KEY,
        aws_secret_access_key=NCP_SECRET_KEY,
        config=cfg,
    )


def fetch_bytes(url: str, attempt: int = 1) -> bytes:
    req = Request(url, headers={"User-Agent": "Codex Plant Image Backfill/1.0", "Connection": "close"})
    try:
        with urlopen(req, timeout=30) as response:
            return response.read()
    except (HTTPError, URLError):
        if attempt >= 5:
            raise
        return fetch_bytes(url, attempt + 1)


def optimize_to_webp(image_bytes: bytes) -> bytes:
    image = Image.open(io.BytesIO(image_bytes))
    image = ImageOps.exif_transpose(image).convert("RGB")
    image.thumbnail((512, 512))
    canvas = Image.new("RGB", (512, 512), (255, 255, 255))
    left = (512 - image.width) // 2
    top = (512 - image.height) // 2
    canvas.paste(image, (left, top))
    output = io.BytesIO()
    canvas.save(output, format="WEBP", quality=88, method=6)
    return output.getvalue()


def upload_to_ncp(s3_client, image_bytes: bytes) -> tuple[str, str]:
    webp_bytes = optimize_to_webp(image_bytes)
    image_path = f"plant-reminder/presets/{uuid.uuid4()}.webp"
    s3_client.put_object(
        Bucket=NCP_BUCKET_NAME,
        Key=image_path,
        Body=webp_bytes,
        ContentType="image/webp",
        ACL="private",
    )
    return f"{CDN_DOMAIN}/{image_path}", image_path


def main() -> None:
    try:
        sys.stdout.reconfigure(encoding="utf-8")
    except Exception:
        pass

    args = parse_args()
    load_env(str(DEFAULT_ENV_PATH))
    conn = create_db_connection()
    s3_client = create_s3_client()
    cursor = conn.cursor(dictionary=True)

    updated = 0
    skipped = 0
    failed: list[dict[str, str]] = []

    try:
        fmt = ",".join(["%s"] * len(args.type_names))
        cursor.execute(
            f"""
            SELECT id, type_name, image_url, image_path
            FROM plant_reminder_presets
            WHERE is_active = 1 AND type_name IN ({fmt})
            ORDER BY id ASC
            """,
            tuple(args.type_names),
        )
        rows = cursor.fetchall()

        for row in rows:
            if row.get("image_path"):
                skipped += 1
                continue
            src = (row.get("image_url") or "").strip()
            if not src:
                failed.append({"type_name": row["type_name"], "reason": "missing image_url"})
                continue
            try:
                if args.dry_run:
                    print(f"[dry-run] {row['type_name']} <- {src}")
                    continue
                img = fetch_bytes(src)
                cdn_url, path = upload_to_ncp(s3_client, img)
                cursor.execute(
                    """
                    UPDATE plant_reminder_presets
                    SET image_url = %s, image_path = %s, updated_at = NOW()
                    WHERE id = %s
                    """,
                    (cdn_url, path, row["id"]),
                )
                conn.commit()
                updated += 1
                print(f"[updated] {row['type_name']} -> {cdn_url}")
            except (ClientError, Exception) as exc:
                failed.append({"type_name": row["type_name"], "reason": str(exc)})

        print({"updated": updated, "skipped": skipped, "failed_count": len(failed), "failed": failed})
    finally:
        cursor.close()
        conn.close()


if __name__ == "__main__":
    main()

