from pathlib import Path
import argparse
import json
import os
import sys
import time
import traceback
from datetime import datetime

BASE_DIR = Path(__file__).resolve().parents[1]
if str(BASE_DIR) not in sys.path:
    sys.path.insert(0, str(BASE_DIR))

from app import (
    app,
    get_db,
    translate_listing_with_ai,
    translate_page_with_ai,
    translate_interface_with_ai,
    translate_faq_with_ai,
    faq_translation_has_content,
    listing_translation_has_content,
    interface_translation_has_content,
    LANGUAGES,
)


def now():
    return datetime.utcnow().replace(microsecond=0).isoformat() + "Z"


def read_state(path):
    try:
        return json.loads(Path(path).read_text(encoding="utf-8"))
    except Exception:
        return {}


def write_state(path, state):
    state = dict(state)
    state["updated_at"] = now()
    Path(path).write_text(json.dumps(state, indent=2), encoding="utf-8")


def build_tasks(config):
    explicit = config.get("explicit_tasks") or []
    if explicit:
        tasks = []
        for item in explicit:
            if isinstance(item, (list, tuple)) and len(item) == 2:
                tasks.append((item[0], item[1]))
        return config.get("content_type", "listings"), tasks, 0

    db = get_db()
    content_type = config.get("content_type", "listings")
    langs = [x for x in config.get("langs", []) if x in LANGUAGES and x != "en"]
    mode = config.get("mode", "missing")
    raw_ids = config.get("ids", [])
    ids = [int(x) for x in raw_ids] if content_type in ("listings", "pages", "faqs") else [str(x) for x in raw_ids]
    all_items = bool(config.get("all_items"))
    tasks = []
    skipped = 0

    if content_type == "listings":
        if all_items:
            rows = db.execute("SELECT * FROM listings WHERE COALESCE(is_deleted,0)=0 ORDER BY id").fetchall()
        elif ids:
            placeholders = ",".join("?" for _ in ids)
            rows = db.execute(f"SELECT * FROM listings WHERE id IN ({placeholders}) ORDER BY id", ids).fetchall()
        else:
            rows = []
        for row in rows:
            for lang in langs:
                if mode == "missing" and listing_translation_has_content(row, lang):
                    skipped += 1
                    continue
                tasks.append((row["id"], lang))
    elif content_type == "pages":
        if all_items:
            rows = db.execute("SELECT * FROM site_pages ORDER BY id").fetchall()
        elif ids:
            placeholders = ",".join("?" for _ in ids)
            rows = db.execute(f"SELECT * FROM site_pages WHERE id IN ({placeholders}) ORDER BY id", ids).fetchall()
        else:
            rows = []
        for row in rows:
            for lang in langs:
                if mode == "missing":
                    status_key = f"translation_status_{lang}"
                    title_key = f"title_{lang}"
                    has_content = bool((row[title_key] or "").strip()) if title_key in row.keys() else False
                    status = row[status_key] if status_key in row.keys() else "missing"
                    if has_content and status not in ("missing", "outdated"):
                        skipped += 1
                        continue
                tasks.append((row["id"], lang))
    elif content_type == "faqs":
        if all_items:
            rows = db.execute("SELECT * FROM faqs WHERE is_active = 1 ORDER BY sort_order, id").fetchall()
        elif ids:
            placeholders = ",".join("?" for _ in ids)
            rows = db.execute(f"SELECT * FROM faqs WHERE id IN ({placeholders}) ORDER BY sort_order, id", ids).fetchall()
        else:
            rows = []
        for row in rows:
            for lang in langs:
                if mode == "missing" and faq_translation_has_content(row, lang):
                    skipped += 1
                    continue
                tasks.append((row["id"], lang))
    else:
        if all_items:
            rows = db.execute("SELECT * FROM interface_translations ORDER BY translation_key").fetchall()
        elif ids:
            placeholders = ",".join("?" for _ in ids)
            rows = db.execute(f"SELECT * FROM interface_translations WHERE translation_key IN ({placeholders}) ORDER BY translation_key", ids).fetchall()
        else:
            rows = []
        for row in rows:
            for lang in langs:
                if mode == "missing" and interface_translation_has_content(row, lang):
                    skipped += 1
                    continue
                tasks.append((row["translation_key"], lang))
    return content_type, tasks, skipped


def control_requested(state_path):
    current = read_state(state_path)
    if current.get("cancel_requested") or current.get("status") in ("cancelled", "cancelling"):
        return "cancel"
    if current.get("pause_requested") or current.get("status") == "pausing":
        return "pause"
    return ""


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--config", required=True)
    parser.add_argument("--state", required=True)
    args = parser.parse_args()
    config = json.loads(Path(args.config).read_text(encoding="utf-8"))
    state = {
        "status": "running",
        "started_at": now(),
        "content_type": config.get("content_type"),
        "mode": config.get("mode"),
        "model": config.get("model"),
        "completed": 0,
        "failed": 0,
        "skipped_existing": 0,
        "total_tasks": 0,
        "current": "",
        "errors": [],
        "failed_tasks": [],
        "remaining_tasks": [],
        "completed_tasks": [],
        "config": config,
        "pid": os.getpid(),
        "pause_requested": False,
        "cancel_requested": False,
    }
    write_state(args.state, state)

    with app.app_context():
        selected_model = (config.get("model") or "").strip()
        if selected_model:
            get_db().execute(
                "UPDATE site_settings SET translation_model = ?, updated_at = ? WHERE id = 1",
                (selected_model, now()),
            )
            get_db().commit()
        content_type, tasks, skipped = build_tasks(config)
        state["content_type"] = content_type
        state["total_tasks"] = len(tasks)
        state["skipped_existing"] = skipped
        state["remaining_tasks"] = [list(task) for task in tasks]
        write_state(args.state, state)
        force = config.get("mode") == "regenerate"

        for index, (item_id, lang) in enumerate(tasks):
            requested = control_requested(args.state)
            if requested == "cancel":
                state["status"] = "cancelled"
                state["finished_at"] = now()
                state["current"] = ""
                state["remaining_tasks"] = [list(task) for task in tasks[index:]]
                write_state(args.state, state)
                return
            if requested == "pause":
                state["status"] = "paused"
                state["paused_at"] = now()
                state["current"] = ""
                state["remaining_tasks"] = [list(task) for task in tasks[index:]]
                state["pause_requested"] = False
                write_state(args.state, state)
                return

            item_label = f"#{item_id}" if content_type in ("listings", "pages", "faqs") else str(item_id)
            state["current"] = f"{content_type.rstrip('s')} {item_label} -> {lang}"
            state["remaining_tasks"] = [list(task) for task in tasks[index:]]
            write_state(args.state, state)

            success = False
            final_error = None
            for task_attempt in range(1, 4):
                try:
                    if content_type == "listings":
                        translate_listing_with_ai(item_id, lang, force=force)
                    elif content_type == "pages":
                        translate_page_with_ai(item_id, lang, force=force, publish=True)
                    elif content_type == "faqs":
                        translate_faq_with_ai(item_id, lang, force=force)
                    else:
                        translate_interface_with_ai(item_id, lang, force=force)
                    get_db().commit()
                    success = True
                    break
                except Exception as exc:
                    get_db().rollback()
                    final_error = exc
                    if task_attempt < 3:
                        time.sleep(2 * task_attempt)

            if success:
                state["completed"] += 1
                state["completed_tasks"].append([item_id, lang])
                state["completed_tasks"] = state["completed_tasks"][-100:]
            else:
                state["failed"] += 1
                state["failed_tasks"].append([item_id, lang])
                state["errors"].append(f"{state['current']}: {final_error}")
                state["errors"] = state["errors"][-30:]
            state["remaining_tasks"] = [list(task) for task in tasks[index + 1 :]]
            write_state(args.state, state)

    state["status"] = "completed" if not state["failed"] else "completed_with_errors"
    state["finished_at"] = now()
    state["current"] = ""
    state["remaining_tasks"] = []
    write_state(args.state, state)


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        pass
    except Exception as exc:
        try:
            p = argparse.ArgumentParser(add_help=False)
            p.add_argument("--state")
            known, _ = p.parse_known_args()
            if known.state:
                current = read_state(known.state)
                current.update(
                    {
                        "status": "failed",
                        "finished_at": now(),
                        "error": str(exc),
                        "traceback": traceback.format_exc(),
                    }
                )
                write_state(known.state, current)
        except Exception:
            pass
        raise
