"""
Lenh `dsg run` — moi profile tu lay SP pending tu API, claim tranh trung.
"""
from __future__ import annotations

import sys
import threading
import time
from concurrent.futures import ThreadPoolExecutor, as_completed

import click

from ..config import load_settings, validate_settings
from ..profile_manager import ensure_profile_exists
from ..browser_launcher import launch_chrome_for_automation, close_chrome
from ..sora_bot import reset_page, create_video, VideoGenLimitReachedError
from ..api_client import get_pending_products, mark_product_done
from ..telegram_notifier import (
    notify_product_done,
    notify_product_failed,
    notify_profile_done,
    notify_profile_limit_reached,
    notify_all_done,
)
from ..run_tracker import record_product_done, record_product_failed
from ..constants import (
    PRODUCTS_PER_PROFILE,
    CDP_PORT_BASE,
)
from .common import _LINE, _BOLD, echo, image_src


def _process_profile(
    profile: dict,
    profile_idx: int,
    settings: dict,
    claim_lock: threading.Lock,
    claimed: set,
    lock: threading.Lock,
    counters: dict,
    counters_lock: threading.Lock,
) -> None:
    """Mot profile: lay SP not_start tu API (claim tranh trung), xu ly toi da PRODUCTS_PER_PROFILE."""
    profile_id = profile["id"]
    alias = profile.get("alias", profile_id)
    debug_port = CDP_PORT_BASE + profile_idx

    profile_path = ensure_profile_exists(profile_id)
    proc = pw = None
    p_done = p_failed = 0
    current_pid: int | None = None

    try:
        proc, pw, _browser, _ctx, page = launch_chrome_for_automation(profile_path, debug_port)

        for product_count in range(PRODUCTS_PER_PROFILE):
            product = None
            with claim_lock:
                try:
                    fresh = get_pending_products(settings["username"])
                except Exception as e:
                    echo(lock, f"  [{alias}] Loi fetch API: {e}")
                    break
                available = [p for p in fresh if p["id"] not in claimed]
                if not available:
                    echo(lock, f"  [{alias}] Khong con san pham nao de xu ly.")
                    break
                product = available[0]
                claimed.add(product["id"])

            current_pid = product["id"]
            pname = product["product_name"]
            prompt = product["prompt_content"]
            image_src_val = image_src(
                product.get("product_image") or product.get("image_url")
            )

            echo(lock, f"\n  [{alias}] [{product_count + 1}/{PRODUCTS_PER_PROFILE}] {pname}")
            echo(lock, f"  Anh: {image_src_val or '(mac dinh)'}")

            try:
                create_video(page, prompt, image_src_val, profile_alias=alias)
                mark_product_done(current_pid, settings["backend_key"])
                p_done += 1
                with counters_lock:
                    counters["done"] += 1
                record_product_done(profile_id, current_pid)
                echo(lock, f"  OK  [{alias}] {pname}")
                notify_product_done(settings, alias, pname)
            except VideoGenLimitReachedError:
                p_failed += 1
                with counters_lock:
                    counters["failed"] += 1
                record_product_failed(profile_id)
                echo(lock, f"  [GIOI HAN] [{alias}] {pname}: da tao toi da video trong ngay.")
                notify_profile_limit_reached(settings, alias)
                echo(lock, f"  [GIOI HAN] {alias}: Tat profile, tiep tuc voi profile khac (neu co).")
                break
            except Exception as e:
                p_failed += 1
                with counters_lock:
                    counters["failed"] += 1
                record_product_failed(profile_id)
                echo(lock, f"  LOI  [{alias}] {pname}: {e}")
                notify_product_failed(settings, alias, pname, str(e))
            finally:
                claimed.discard(current_pid)
                current_pid = None

            if product_count < PRODUCTS_PER_PROFILE - 1:
                with claim_lock:
                    try:
                        check = get_pending_products(settings["username"])
                        has_more = any(p["id"] not in claimed for p in check)
                    except Exception:
                        has_more = True
                if not has_more:
                    echo(lock, f"  [{alias}] Het san pham, ket thuc som.")
                    break
                wait_min = settings.get("wait_between_products_min", 10)
                wait_sec = wait_min * 60
                echo(lock, f"\n  [{alias}] Cho {wait_min} phut de gen video ...")
                time.sleep(wait_sec)
                echo(lock, f"  [{alias}] F5 trang ...")
                reset_page(page, profile_alias=alias)

    except Exception as e:
        echo(lock, f"\n  LOI NGHIEM TRONG ({alias}): {e}")
        if current_pid is not None:
            claimed.discard(current_pid)
        with counters_lock:
            counters["failed"] += max(0, PRODUCTS_PER_PROFILE - p_done - p_failed)
    finally:
        if pw:
            try:
                pw.stop()
            except Exception:
                pass
        if proc:
            close_chrome(proc)
            echo(lock, f"\n  Da dong Chrome: {alias}")

    echo(lock, f"\n  {alias}: OK {p_done} | LOI {p_failed}")
    notify_profile_done(settings, alias, p_done, p_failed)


def cmd_run() -> None:
    """Chay tu dong tao video: moi profile lay SP not_start tu API, claim tranh trung."""
    settings = load_settings()

    try:
        validate_settings(settings)
    except ValueError as e:
        click.echo(f"Loi cau hinh: {e}", err=True)
        sys.exit(1)

    profiles = settings["profiles"]
    concurrent = max(1, settings.get("concurrent_profiles", 1))
    print_lock = threading.Lock()
    counters: dict = {"done": 0, "failed": 0}
    counters_lock = threading.Lock()
    claim_lock = threading.Lock()
    claimed: set = set()

    click.echo(f"\n{_BOLD}")
    click.echo("  SORA VIDEO TOOL — CHAY")
    click.echo(_BOLD)
    click.echo(f"  Username      : {settings['username']}")
    click.echo(f"  Profiles      : {len(profiles)}")
    click.echo(f"  Chay cung luc : {concurrent}")
    click.echo(_BOLD)

    with ThreadPoolExecutor(max_workers=concurrent) as pool:
        futures = [
            pool.submit(
                _process_profile,
                profile, idx, settings,
                claim_lock, claimed,
                print_lock, counters, counters_lock,
            )
            for idx, profile in enumerate(profiles)
        ]
        for f in as_completed(futures):
            try:
                f.result()
            except Exception as e:
                click.echo(f"  LOI THREAD: {e}")

    click.echo(f"\n{_BOLD}")
    click.echo("  HOAN TAT")
    click.echo(_BOLD)
    click.echo(f"  Thanh cong : {counters['done']}")
    click.echo(f"  Loi        : {counters['failed']}")
    click.echo(f"  Tong       : {counters['done'] + counters['failed']}")
    click.echo(_BOLD)

    notify_all_done(settings, counters["done"], counters["failed"])


def register_run(main: click.Group) -> None:
    main.command("run")(cmd_run)
