"""Terminal UI for Superpitch."""

from __future__ import annotations

import sys
from pathlib import Path
from textwrap import dedent

try:
    import termios
    import tty
except ImportError:
    termios = None
    tty = None

from superpitch.app_paths import APP_HOME, APP_NAME, FEEDBACK_FILE
from superpitch.core import collect_feedback, evaluate_pitch
from superpitch.state import (
    inbox_counts,
    load_config,
    load_history,
    mark_pitch_opened,
    ordered_history,
    profile_status_line,
    save_config,
    save_history_entry,
    update_history_item,
    history_bucket,
)


def supports_keypress_ui():
    return bool(sys.stdin.isatty() and sys.stdout.isatty() and termios is not None and tty is not None)


def read_keypress():
    if not supports_keypress_ui():
        return input().strip().lower()

    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(fd)
        first = sys.stdin.read(1)
        if first == "\x03":
            raise KeyboardInterrupt
        if first in ("\r", "\n"):
            return "ENTER"
        if first == "\x1b":
            second = sys.stdin.read(1)
            if second == "[":
                third = sys.stdin.read(1)
                if third == "A":
                    return "UP"
                if third == "B":
                    return "DOWN"
            return "ESC"
        return first.lower()
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)


def clear_screen():
    if supports_keypress_ui():
        print("\033[2J\033[H", end="")


def print_brand():
    print("  ____                             _ _       _     ")
    print(" / ___| _   _ _ __   ___ _ __ _ __(_) |_ ___| |__  ")
    print(" \\___ \\| | | | '_ \\ / _ \\ '__| '_ \\ | __/ __| '_ \\ ")
    print("  ___) | |_| | |_) |  __/ |  | |_) | | || (__| | | |")
    print(" |____/ \\__,_| .__/ \\___|_|  | .__/|_|\\__\\___|_| |_|")
    print("             |_|             |_|                    ")


def onboarding_flow(created_files):
    config = load_config()
    if config.get("onboarding_complete"):
        return config

    clear_screen()
    print_brand()
    print()
    print(f"  Welcome to {APP_NAME}")
    if created_files:
        print(f"  Local files live in {APP_HOME}")
        print("  Seed model and starter memory were copied locally.")
        print()
    print("  [1] Sign in")
    print("  [2] Use locally")
    print("  [q] Quit")

    while True:
        print("\n  > ", end="", flush=True)
        choice = read_keypress()
        if choice == "1":
            print("\n  Signed-in mode is not live yet.")
            print("  Tomorrow this will open superpitch.dev/auth and sync your inbox.")
            print("  For now, choose Use locally.")
            continue
        if choice in {"2", "", "ENTER"}:
            config["mode"] = "local"
            config["signed_in"] = False
            break
        if choice in {"q", "quit", "exit"}:
            raise SystemExit(0)

    config["onboarding_complete"] = True
    save_config(config)
    return config


def read_raw_text():
    print("  Paste pitch text (empty line to finish):")
    lines = []
    while True:
        try:
            line = input()
        except EOFError:
            break
        if line == "":
            break
        lines.append(line)
    return "\n".join(lines)


def normalize_dropped_path(raw_path: str):
    path_text = raw_path.strip()
    if not path_text:
        return None
    if len(path_text) >= 2 and path_text[0] == path_text[-1] and path_text[0] in {"'", '"'}:
        path_text = path_text[1:-1]
    return Path(path_text.replace("\\ ", " ")).expanduser()


def supported_pitch_files(folder: Path):
    allowed = {".txt", ".md", ".rtf", ".json", ".jsonl"}
    return sorted(
        p for p in folder.iterdir()
        if p.is_file() and p.suffix.lower() in allowed and not p.name.startswith(".")
    )


def read_pitch_file(path: Path):
    return path.read_text(encoding="utf-8", errors="ignore")


def read_path_input():
    print("  Drop a file or folder path here, then press enter:")
    dropped = normalize_dropped_path(input("  Path: "))
    if dropped is None or not dropped.exists():
        print("  Path not found.")
        return None, []
    if dropped.is_dir():
        files = supported_pitch_files(dropped)
        if not files:
            print("  No supported files found in that folder.")
            return None, []
        return None, files
    return dropped, []


def print_result(result):
    print("\n" + "=" * 55)
    print(f"  {result['final_action']}  {result['pred_score']:.1f}/10")
    sub = result["sub"]
    print(f"  Team {sub['team']:.1f}  ·  Traction {sub['traction']:.1f}  ·  Market {sub['market']:.1f}  ·  Risk {sub['risk']:.1f}")
    print(f"  Confidence: {result['confidence']['level']}")
    if result["review_reasons"]:
        print(f"  Review: {', '.join(result['review_reasons'])}")
    signals = result["signals"]
    if signals["positive"]:
        print(f"  Positive: {', '.join(signals['positive'])}")
    if signals["negative"]:
        print(f"  Risks: {', '.join(signals['negative'])}")
    print("=" * 55)


def prompt_input(label="  /"):
    return input(f"\n{label} ").strip()


def print_help():
    print()
    print(dedent("""
      Commands
      /open 1        open pitch 1
      /approve 1     mark pitch 1 approve
      /reject 1      mark pitch 1 reject
      /review 1      mark pitch 1 review
      /add           paste a pitch manually
      /today         show today's pitches
      /all           show all queued pitches
      /sync          sync inbox (disabled for now)
      /profile       show local profile
      /help          show commands
      /quit          exit
    """).strip("\n"))


def process_pitch(bundle, text, index_vecs, examples, pitch=None, source_label="manual", request_feedback=True):
    result = evaluate_pitch(bundle, text, index_vecs=index_vecs, examples=examples, inp=pitch)
    print_result(result)
    save_history_entry(text, pitch, result, source_label)
    if request_feedback:
        collect_feedback(
            text,
            result["pred_score"],
            result["final_action"],
            inp=pitch,
            confidence=result["confidence"],
            signals=result["signals"],
            diagnostics=result["diagnostics"],
            is_moonshot=result["is_moonshot"],
        )


def add_pitch_flow(bundle, index_vecs, examples):
    while True:
        print("\n" + "-" * 55)
        print("  Add pitch")
        print("  [1] Paste pitch text")
        print("  [2] Drop a file or folder path")
        print("  [b] Back")
        print("\n  > ", end="", flush=True)
        choice = read_keypress()

        if choice in {"b", "back", "q", "quit"}:
            return
        if choice == "1":
            text = read_raw_text()
            if text.strip():
                process_pitch(bundle, text, index_vecs, examples, pitch=None, source_label="pasted text")
                return
        elif choice == "2":
            path, folder_files = read_path_input()
            if path is None and not folder_files:
                continue
            if path is not None:
                process_pitch(bundle, read_pitch_file(path), index_vecs, examples, source_label=str(path))
                return
            print(f"  Scoring {len(folder_files)} files from {folder_files[0].parent}")
            for item in folder_files:
                print(f"\n  -> {item.name}")
                process_pitch(
                    bundle,
                    read_pitch_file(item),
                    index_vecs,
                    examples,
                    source_label=str(item),
                    request_feedback=False,
                )
            return


def print_inbox(config, selected=0, view="top"):
    items = load_history()
    counts = inbox_counts(items)
    ranked_all = ordered_history(items)
    if view == "today":
        ranked = [
            pair for pair in ranked_all
            if pair[1].get("timestamp", "")[:10] == __import__("datetime").datetime.now().date().isoformat()
        ][:12]
    elif view == "all":
        ranked = ranked_all[:20]
    else:
        ranked = ranked_all[:8]
    selected = max(0, min(selected, len(ranked) - 1)) if ranked else 0
    clear_screen()
    print_brand()
    print()
    print(f"  {counts['new']} new  ·  {counts['seen']} seen  ·  {counts['decided']} decided")
    print(f"  {profile_status_line(config)}")
    if not ranked:
        print("  No pitches yet.")
        print("  Use /add to paste your first pitch.")
    else:
        title = {
            "top": "Top unattended pitches",
            "today": "Today's pitches",
            "all": "All queued pitches",
        }[view]
        print(f"  {title}")
        for display_idx, (_real_idx, item) in enumerate(ranked, start=1):
            title = (item.get("one_liner") or "(untitled pitch)")[:48]
            bucket = history_bucket(item).upper()
            label = (item.get("decision_state") or item.get("final_action") or "").upper()
            cursor = ">" if display_idx - 1 == selected else " "
            print(f" {cursor} [{display_idx}] {bucket:7s} {label:7s} {item['pred_score']:.1f}/10  {title}")
    print()
    print("  Type /help for commands.")
    return ranked, selected


def pitch_detail_flow(indexed_items, selected):
    if not indexed_items:
        return
    real_index, item = indexed_items[selected]
    item = mark_pitch_opened(real_index, item)

    while True:
        clear_screen()
        print("-" * 55)
        print(f"  Model action: {item['final_action']}  {item['pred_score']:.1f}/10")
        print(f"  Queue state: {history_bucket(item)}")
        if item.get("decision_state"):
            print(f"  Your decision: {item['decision_state']}")
        print(f"  Title: {(item.get('one_liner') or '(untitled pitch)')[:120]}")
        print(f"  Source: {item['source_label']}")
        if item["review_reasons"]:
            print(f"  Review: {', '.join(item['review_reasons'])}")
        print()
        print("  [1] Mark approve")
        print("  [2] Mark reject")
        print("  [3] Mark review")
        print("  [b] Back")
        print("\n  > ", end="", flush=True)
        choice = read_keypress()
        if choice in {"b", "back", "q", "quit", ""}:
            return
        if choice == "1":
            item["decision_state"] = "approve"
        elif choice == "2":
            item["decision_state"] = "reject"
        elif choice == "3":
            item["decision_state"] = "review"
        else:
            continue
        from datetime import datetime
        item["decided_at"] = datetime.now().isoformat()
        update_history_item(real_index, item)
        return


def profile_flow(config):
    clear_screen()
    print_brand()
    print()
    print("  Profile")
    print(f"  Status: {profile_status_line(config)}")
    print(f"  Mode: {config.get('mode', 'local')}")
    print(f"  Storage: {APP_HOME}")
    print(f"  Feedback file: {FEEDBACK_FILE}")
    if config.get("mode") == "cloud":
        print("  Sync polling: disabled until signed-in mode ships")
    print("  Press enter to go back.")

    while True:
        choice = prompt_input("  ")
        if choice in {"", "b", "back", "q", "quit"}:
            return config


def update_pitch_decision(indexed_items, display_index, decision):
    if display_index < 1 or display_index > len(indexed_items):
        print("  Pitch not found.")
        return
    real_index, item = indexed_items[display_index - 1]
    item = mark_pitch_opened(real_index, item)
    item["decision_state"] = decision
    item["decided_at"] = __import__("datetime").datetime.now().isoformat()
    update_history_item(real_index, item)


def handle_command(command, ranked, config, bundle, index_vecs, examples):
    if not command:
        return {"quit": False, "view": "top"}

    if command in {"/quit", "/q", "q"}:
        return {"quit": True, "view": "top"}
    if command == "/help":
        print_help()
        input("\n  Press enter to continue...")
        return {"quit": False, "view": "top"}
    if command in {"/add", "/add manually"}:
        add_pitch_flow(bundle, index_vecs, examples)
        return {"quit": False, "view": "top"}
    if command == "/profile":
        profile_flow(config)
        return {"quit": False, "view": "top"}
    if command == "/sync":
        print("\n  Sync is not live yet.")
        print("  Tomorrow this will pull new pitches from your hosted inbox every 15 minutes.")
        input("\n  Press enter to continue...")
        return {"quit": False, "view": "top"}
    if command == "/today":
        return {"quit": False, "view": "today"}
    if command == "/all":
        return {"quit": False, "view": "all"}
    if command.startswith("/open "):
        try:
            number = int(command.split()[1])
        except (IndexError, ValueError):
            print("  Use /open 1")
            input("\n  Press enter to continue...")
            return {"quit": False, "view": "top"}
        pitch_detail_flow(ranked, number - 1)
        return {"quit": False, "view": "top"}
    if command.startswith("/approve "):
        try:
            number = int(command.split()[1])
        except (IndexError, ValueError):
            print("  Use /approve 1")
            input("\n  Press enter to continue...")
            return {"quit": False, "view": "top"}
        update_pitch_decision(ranked, number, "approve")
        return {"quit": False, "view": "top"}
    if command.startswith("/reject "):
        try:
            number = int(command.split()[1])
        except (IndexError, ValueError):
            print("  Use /reject 1")
            input("\n  Press enter to continue...")
            return {"quit": False, "view": "top"}
        update_pitch_decision(ranked, number, "reject")
        return {"quit": False, "view": "top"}
    if command.startswith("/review "):
        try:
            number = int(command.split()[1])
        except (IndexError, ValueError):
            print("  Use /review 1")
            input("\n  Press enter to continue...")
            return {"quit": False, "view": "top"}
        update_pitch_decision(ranked, number, "review")
        return {"quit": False, "view": "top"}

    print("\n  Unknown command.")
    print("  Type /help")
    input("\n  Press enter to continue...")
    return {"quit": False, "view": "top"}


def run_interactive_app(bundle, index_vecs, examples, created_files):
    config = onboarding_flow(created_files)

    if FEEDBACK_FILE.exists():
        with open(FEEDBACK_FILE) as f:
            n_feedback = sum(1 for line in f if line.strip())
        if n_feedback:
            print(f"Your feedback: {n_feedback} labeled pitches.")

    view = "top"
    while True:
        ranked, _selected = print_inbox(config, view=view)
        command = prompt_input()
        result = handle_command(command, ranked, config, bundle, index_vecs, examples)
        view = result.get("view", "top")
        if result.get("quit"):
            break
