from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

SCRIPT_DIR = Path(__file__).resolve().parent
if str(SCRIPT_DIR) not in sys.path:
    sys.path.insert(0, str(SCRIPT_DIR))
for dep_dir in [SCRIPT_DIR / ".pydeps", SCRIPT_DIR.parent / ".pydeps", Path.cwd() / ".pydeps"]:
    if dep_dir.exists() and str(dep_dir) not in sys.path:
        sys.path.insert(0, str(dep_dir))

from PIL import Image, ImageDraw, ImageFont
import yaml

from runtime_config import add_config_source_args, load_runtime_config


def load_font(size: int, *, bold: bool = False) -> ImageFont.ImageFont:
    candidates: list[str] = []
    if bold:
        candidates.extend([r"C:\Windows\Fonts\msyhbd.ttc", r"C:\Windows\Fonts\simhei.ttf", r"C:\Windows\Fonts\arialbd.ttf"])
    candidates.extend([r"C:\Windows\Fonts\msyh.ttc", r"C:\Windows\Fonts\simsun.ttc", r"C:\Windows\Fonts\arial.ttf"])
    for path in candidates:
        try:
            return ImageFont.truetype(path, size=size)
        except OSError:
            continue
    return ImageFont.load_default()


def resize_to_width(img: Image.Image, width: int) -> Image.Image:
    if img.width == width:
        return img
    target_h = int(img.height * width / img.width)
    return img.resize((width, target_h), Image.Resampling.LANCZOS)


def scale_image(img: Image.Image, factor: float) -> Image.Image:
    if abs(factor - 1.0) < 1e-6:
        return img
    w = max(1, int(img.width * factor))
    h = max(1, int(img.height * factor))
    # For chart/table text assets, NEAREST keeps stroke edges crisper than smooth interpolation.
    return img.resize((w, h), Image.Resampling.NEAREST)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Compose livestream report image from 3 source images.")
    add_config_source_args(parser, default_config=Path(r"D:\projects\skills\vip-report\config.yaml"))
    parser.add_argument("--summary-image", default="")
    parser.add_argument("--trend-image", default="")
    parser.add_argument("--pivot-image", default="")
    parser.add_argument("--output", default="")
    parser.add_argument("--content-width", type=int, default=0, help="0 means keep source widths and center align.")
    parser.add_argument("--summary-crop-top", type=int, default=52)
    parser.add_argument("--summary-scale", type=float, default=1.8)
    parser.add_argument("--trend-scale", type=float, default=1.3)
    parser.add_argument("--pivot-scale", type=float, default=1.0)
    return parser.parse_args()


def default_paths_from_config(config: dict) -> dict[str, Path]:
    workdir = Path(config["paths"]["workdir"]).resolve()
    assets = workdir / "assets"
    return {
        "summary": assets / "cep-live-session" / "cep-live-session-summary.png",
        "trend": assets / "cep-live-session" / "cep-live-session-sales-penetration-trend.png",
        "pivot": assets / "cep-live-goods-effect" / "cep-live-goods-effect-pivot.png",
        "output": assets / "cep-live-session" / "cep-live-session-combined.png",
    }


def resolve_path(arg_value: str, default: Path) -> Path:
    return Path(arg_value).resolve() if arg_value else default


def main() -> None:
    args = parse_args()
    config_path = Path(args.config or r"D:\projects\skills\vip-report\config.yaml").resolve()
    config = load_runtime_config(args, default_config=config_path)
    defaults = default_paths_from_config(config)

    summary_path = resolve_path(args.summary_image, defaults["summary"])
    trend_path = resolve_path(args.trend_image, defaults["trend"])
    pivot_path = resolve_path(args.pivot_image, defaults["pivot"])
    output_path = resolve_path(args.output, defaults["output"])

    for p in [summary_path, trend_path, pivot_path]:
        if not p.exists():
            raise FileNotFoundError(f"missing source image: {p}")

    summary_img = Image.open(summary_path).convert("RGB")
    if args.summary_crop_top > 0 and args.summary_crop_top < summary_img.height:
        summary_img = summary_img.crop((0, args.summary_crop_top, summary_img.width, summary_img.height))
    trend_img = Image.open(trend_path).convert("RGB")
    pivot_img = Image.open(pivot_path).convert("RGB")

    summary_img = scale_image(summary_img, args.summary_scale)
    trend_img = scale_image(trend_img, args.trend_scale)
    pivot_img = scale_image(pivot_img, args.pivot_scale)

    if args.content_width > 0:
        summary_img = resize_to_width(summary_img, args.content_width)
        trend_img = resize_to_width(trend_img, args.content_width)
        pivot_img = resize_to_width(pivot_img, args.content_width)

    pad_x = 34
    top_h = 56
    gap = 10
    bottom_pad = 18
    content_w = max(summary_img.width, trend_img.width, pivot_img.width)
    canvas_w = content_w + pad_x * 2
    canvas_h = top_h + summary_img.height + gap + trend_img.height + gap + pivot_img.height + bottom_pad

    canvas = Image.new("RGB", (canvas_w, canvas_h), "#e7e7e7")
    draw = ImageDraw.Draw(canvas)

    title_font = load_font(36, bold=True)
    brand_font = load_font(24, bold=True)
    draw.text((pad_x, 14), "LIVESTREAM", fill="#111111", font=title_font)
    draw.text((canvas_w - 176, 18), "CHARLES & KEITH", fill="#c9c9c9", font=brand_font)

    y = top_h
    canvas.paste(summary_img, (pad_x + (content_w - summary_img.width) // 2, y))
    y += summary_img.height + gap
    canvas.paste(trend_img, (pad_x + (content_w - trend_img.width) // 2, y))
    y += trend_img.height + gap
    canvas.paste(pivot_img, (pad_x + (content_w - pivot_img.width) // 2, y))

    output_path.parent.mkdir(parents=True, exist_ok=True)
    canvas.save(output_path)
    print(json.dumps({"ok": True, "image_path": str(output_path)}, ensure_ascii=False))


if __name__ == "__main__":
    main()
