"""Rich TUI display + main loop."""

import select
import subprocess
import sys
import termios
import time
import tty

from rich.console import Console, Group
from rich.table import Table
from rich.panel import Panel
from rich.text import Text
from rich.live import Live

from project_manager_tui.config import Config
from project_manager_tui.core import (
    activate_task,
    add_task_to_project,
    delete_task,
    ensure_task_md,
    get_all_active_tasks,
    get_current_branch,
    get_project_list,
    get_worktree_list_output,
    mark_task_released,
    mark_task_verified,
    move_project_to_section,
    parse_tasks,
    snooze_task,
    unsnooze_task,
)


def get_key(timeout=None):
  """Read a single keypress from stdin with optional timeout."""
  fd = sys.stdin.fileno()
  old_settings = termios.tcgetattr(fd)
  try:
    tty.setraw(fd)
    if timeout is not None:
      ready, _, _ = select.select([sys.stdin], [], [], timeout)
      if not ready:
        return None
    ch = sys.stdin.read(1)
  finally:
    termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
  return ch


def build_display(tasks, selected_idx, show_help=False, show_verified=False, show_snoozed=False, show_blocked=False, show_working=False, current_branch=None):
  """Build the display renderable."""
  table = Table(show_header=False, box=None, padding=(0, 0), pad_edge=False)
  table.add_column(width=5, no_wrap=True)
  table.add_column(width=24, no_wrap=True, overflow="ellipsis")
  table.add_column(no_wrap=True, overflow="ellipsis")

  for i, task in enumerate(tasks):
    wt_status = task.get("worktree_status", "")
    state_display = f"[{task['state']}]{wt_status}"

    state = task.get("state", " ")
    if task.get("verified"):
      state_style = "cyan"
      row_color = "cyan"
    elif task["done"]:
      state_style = "green"
      row_color = "green"
    elif task.get("snoozed"):
      state_style = "magenta"
      row_color = "magenta"
    elif state == "r":
      state_style = "yellow"
      row_color = "yellow"
    elif state == "t":
      state_style = "blue"
      row_color = "blue"
    elif not task.get("deps_met", True):
      state_style = "red"
      row_color = "red"
    else:
      state_style = "white"
      row_color = ""

    if i == selected_idx:
      select_style = "reverse"
      state_style = f"{state_style} reverse"
      name_style = f"{row_color} reverse" if row_color else "reverse"
    else:
      select_style = ""
      name_style = row_color if row_color else ""

    task_branch = f"{task['project_slug']}-{task['task_num']}"
    current_marker = "*" if current_branch == task_branch else ""

    desc = task["desc"]
    table.add_row(
        Text(state_display, style=state_style),
        Text(f" {task_branch}{current_marker}", style=name_style),
        Text(desc, style=select_style),
    )

  if show_help:
    help_text = Panel(
        "[bold]Task View:[/bold]\n"
        "  j/k  Navigate\n"
        "  t    Vim Task.md\n"
        "  p    Vim Project.md\n"
        "  v    View worktree (awt view)\n"
        "  s    Switch worktree (awt switch)\n"
        "  z    Snooze/unsnooze\n"
        "  c    Complete (close)\n"
        "  r    Release (mark [r])\n"
        "  d    Delete task\n"
        "  V/Z/B/W Toggle verified/snoozed/blocked/working\n"
        "  P    Project view\n"
        "\n[bold]Project View:[/bold]\n"
        "  j/k  Navigate\n"
        "  n    New task\n"
        "  p    Vim Project.md\n"
        "  v    Vim Projects.md\n"
        "  a    Archive project\n"
        "  T    Task view\n"
        "\n[bold]General:[/bold]\n"
        "  ?    Toggle help\n"
        "  q    Quit",
        title="Help",
        border_style="green",
    )
    return Group(table, help_text)
  else:
    status = "[dim]? for help, q to quit[/dim]"
    if show_verified:
      status += " [cyan](+verified)[/cyan]"
    if show_snoozed:
      status += " [magenta](+snoozed)[/magenta]"
    if show_blocked:
      status += " [red](+blocked)[/red]"
    if show_working:
      status += " [yellow](+working)[/yellow]"
    return Group(table, Text.from_markup(status))


def build_project_display(projects, selected_idx):
  """Build the project selection display."""
  table = Table(show_header=False, box=None, padding=(0, 0), pad_edge=False)
  table.add_column(width=10)
  table.add_column()

  section_styles = {
      "Active": "green",
      "Future": "yellow",
      "Archived": "dim",
  }

  current_section = None
  for i, proj in enumerate(projects):
    if proj["section"] != current_section:
      current_section = proj["section"]
      section_display = current_section
    else:
      section_display = ""

    section_style = section_styles.get(proj["section"], "white")

    if i == selected_idx:
      row_style = "reverse"
    else:
      row_style = ""

    table.add_row(
        Text(section_display, style=section_style),
        proj["slug"],
        style=row_style,
    )

  status = "[dim]j/k navigate, n new task, p vim Project.md, v vim Projects.md, a archive, T task view, q quit[/dim]"
  return Group(table, Text.from_markup(status))


def main(config: Config):
  console = Console()

  tasks = get_all_active_tasks(config)
  projects = get_project_list(config)

  if not tasks and not projects:
    # Create minimal Projects.md to bootstrap
    config.projects_dir.mkdir(parents=True, exist_ok=True)
    config.projects_file.write_text(
        "## Active\nsample-project\n\n## Future\n\n## Archived\n")
    sample_dir = config.projects_dir / "sample-project"
    sample_dir.mkdir(exist_ok=True)
    (sample_dir /
     "Project.md").write_text("# Sample Project\n\n\n\n## Tasks\n1. [ ] First task\n")
    console.print("[green]Created sample project. Restart to begin.[/green]")
    return

  view = ['task']
  task_idx = [0]
  proj_idx = [0]
  show_help = False
  show_verified = [False]
  show_snoozed = [False]
  show_blocked = [False]
  show_working = [True]
  current_branch = [get_current_branch(config)]
  last_sync_time = [time.time()]

  def visible_tasks():
    result = tasks
    if not show_verified[0]:
      result = [t for t in result if not t.get("verified")]
    if not show_snoozed[0]:
      result = [t for t in result if not t.get("snoozed")]
    if not show_blocked[0]:
      result = [t for t in result if t.get("deps_met", True)]
    if not show_working[0]:
      result = [t for t in result if t.get("worktree_status") != "\u23f3"]
    return result

  def current_display():
    if view[0] == 'task':
      return build_display(visible_tasks(), task_idx[0], show_help, show_verified[0], show_snoozed[0], show_blocked[0], show_working[0], current_branch[0])
    else:
      return build_project_display(projects, proj_idx[0])

  with Live(current_display(), console=console, screen=True, auto_refresh=False) as live:
    try:
      while True:
        key = get_key(timeout=5)

        if key is None:
          tasks = get_all_active_tasks(config)
          current_branch[0] = get_current_branch(config)
          task_idx[0] = min(task_idx[0], max(0, len(visible_tasks()) - 1))
          if time.time() - last_sync_time[0] >= config.sync_interval:
            subprocess.run(
                [str(config.agent_worktree_script), "sync-master"],
                capture_output=True)
            last_sync_time[0] = time.time()
          live.update(current_display(), refresh=True)
          continue

        if key == "q":
          break

        elif key == "j" or key == "\x1b":
          if key == "\x1b":
            next1 = sys.stdin.read(1) if sys.stdin else ""
            next2 = sys.stdin.read(1) if sys.stdin else ""
            if next1 == "[" and next2 == "B":
              if view[0] == 'task':
                task_idx[0] = min(task_idx[0] + 1, max(0, len(visible_tasks()) - 1))
              else:
                proj_idx[0] = min(proj_idx[0] + 1, len(projects) - 1)
            elif next1 == "[" and next2 == "A":
              if view[0] == 'task':
                task_idx[0] = max(task_idx[0] - 1, 0)
              else:
                proj_idx[0] = max(proj_idx[0] - 1, 0)
          else:
            if view[0] == 'task':
              task_idx[0] = min(task_idx[0] + 1, max(0, len(visible_tasks()) - 1))
            else:
              proj_idx[0] = min(proj_idx[0] + 1, len(projects) - 1)
        elif key == "k":
          if view[0] == 'task':
            task_idx[0] = max(task_idx[0] - 1, 0)
          else:
            proj_idx[0] = max(proj_idx[0] - 1, 0)

        elif key == "T":
          view[0] = 'task'
        elif key == "P":
          vis = visible_tasks()
          if vis and task_idx[0] < len(vis):
            current_project = vis[task_idx[0]]["project_slug"]
            for i, p in enumerate(projects):
              if p["slug"] == current_project:
                proj_idx[0] = i
                break
          view[0] = 'project'

        elif view[0] == 'task':
          if key == "V":
            show_verified[0] = not show_verified[0]
            task_idx[0] = min(task_idx[0], max(0, len(visible_tasks()) - 1))
          elif key == "Z":
            show_snoozed[0] = not show_snoozed[0]
            task_idx[0] = min(task_idx[0], max(0, len(visible_tasks()) - 1))
          elif key == "B":
            show_blocked[0] = not show_blocked[0]
            task_idx[0] = min(task_idx[0], max(0, len(visible_tasks()) - 1))
          elif key == "W":
            show_working[0] = not show_working[0]
            task_idx[0] = min(task_idx[0], max(0, len(visible_tasks()) - 1))
          elif key == "s":
            vis = visible_tasks()
            if vis:
              task = vis[task_idx[0]]
              worktree_name = f"{task['project_slug']}-{task['task_num']}"
              result = subprocess.run(
                  ["tmux", "display-message", "-p", "#{window_index}"],
                  capture_output=True, text=True)
              original_window = result.stdout.strip() if result.returncode == 0 else None
              live.stop()
              subprocess.run(
                  [str(config.agent_worktree_script), "switch", worktree_name])
              current_branch[0] = get_current_branch(config)
              if original_window:
                subprocess.run(["tmux", "select-window", "-t", f":{original_window}"])
              live.start()
          elif key == "z":
            vis = visible_tasks()
            if vis:
              task = vis[task_idx[0]]
              if task.get("snoozed"):
                unsnooze_task(task["project_md_path"], task["task_num"])
              else:
                snooze_task(task["project_md_path"], task["task_num"])
              tasks = get_all_active_tasks(config)
              task_idx[0] = min(task_idx[0], max(0, len(visible_tasks()) - 1))
          elif key == "c":
            vis = visible_tasks()
            if vis:
              task = vis[task_idx[0]]
              confirm_text = Text.from_markup(
                  f"[bold green]Complete task?[/bold green]\n\n"
                  f"  {task['project_slug']}-{task['task_num']}: {task['desc']}\n\n"
                  f"This will remove the worktree and mark task as done.\n\n"
                  f"[bold]Press 'y' to confirm, any other key to cancel[/bold]"
              )
              live.update(confirm_text, refresh=True)
              confirm_key = get_key()
              if confirm_key == "y":
                worktree_name = f"{task['project_slug']}-{task['task_num']}"
                live.stop()
                success = True
                agent_worktree = config.agent_worktree_script
                if agent_worktree.exists() and task["in_worktree"]:
                  result = subprocess.run([str(agent_worktree), "rm", worktree_name])
                  if result.returncode != 0:
                    success = False
                    print("\nPress Enter to continue...")
                    input()
                if success:
                  mark_task_verified(task["project_md_path"], task["task_num"])
                tasks = get_all_active_tasks(config)
                task_idx[0] = min(task_idx[0], max(0, len(visible_tasks()) - 1))
                live.start()
          elif key == "t":
            vis = visible_tasks()
            if vis:
              task = vis[task_idx[0]]
              task_md = ensure_task_md(
                  config, task["project_md_path"], task["project_slug"], task["task_num"], task["desc"])
              live.stop()
              subprocess.run([config.editor, str(task_md)])
              tasks = get_all_active_tasks(config)
              task_idx[0] = min(task_idx[0], max(0, len(visible_tasks()) - 1))
              live.start()
          elif key == "p":
            vis = visible_tasks()
            if vis:
              task = vis[task_idx[0]]
              project_md = task["project_md_path"]
              line_num = task["line_num"]
              live.stop()
              subprocess.run([config.editor, f"+{line_num}", str(project_md)])
              tasks = get_all_active_tasks(config)
              task_idx[0] = min(task_idx[0], max(0, len(visible_tasks()) - 1))
              live.start()
          elif key == "v":
            vis = visible_tasks()
            if vis:
              task = vis[task_idx[0]]
              ensure_task_md(config, task["project_md_path"],
                             task["project_slug"], task["task_num"], task["desc"])
              worktree_name = f"{task['project_slug']}-{task['task_num']}"
              live.stop()
              subprocess.run(
                  [str(config.agent_worktree_script), "view", worktree_name])
              live.start()
          elif key == "r":
            vis = visible_tasks()
            if vis:
              task = vis[task_idx[0]]
              confirm_text = Text.from_markup(
                  f"[bold yellow]Release task?[/bold yellow]\n\n"
                  f"  {task['project_slug']}-{task['task_num']}: {task['desc']}\n\n"
                  f"[bold]Press 'y' to confirm, any other key to cancel[/bold]"
              )
              live.update(confirm_text, refresh=True)
              confirm_key = get_key()
              if confirm_key == "y":
                mark_task_released(task["project_md_path"], task["task_num"])
                tasks = get_all_active_tasks(config)
                task_idx[0] = min(task_idx[0], max(0, len(visible_tasks()) - 1))
          elif key == "d":
            vis = visible_tasks()
            if vis:
              task = vis[task_idx[0]]
              confirm_text = Text.from_markup(
                  f"[bold red]Delete task?[/bold red]\n\n"
                  f"  {task['project_slug']}-{task['task_num']}: {task['desc']}\n\n"
                  f"This will remove the worktree, Task.md, and task line.\n\n"
                  f"[bold]Press 'y' to confirm, any other key to cancel[/bold]"
              )
              live.update(confirm_text, refresh=True)
              confirm_key = get_key()
              if confirm_key == "y":
                live.stop()
                success = delete_task(config, task["project_slug"], task["task_num"])
                if not success:
                  print("\nDelete failed. Press Enter to continue...")
                  input()
                tasks = get_all_active_tasks(config)
                task_idx[0] = min(task_idx[0], max(0, len(visible_tasks()) - 1))
                live.start()
          elif key == "?":
            show_help = not show_help

        elif view[0] == 'project':
          if key == "p":
            if projects:
              selected_project = projects[proj_idx[0]]
              project_md = config.projects_dir / selected_project["slug"] / "Project.md"
              if project_md.exists():
                live.stop()
                subprocess.run([config.editor, str(project_md)])
                tasks = get_all_active_tasks(config)
                live.start()
          elif key == "v":
            if projects:
              selected_project = projects[proj_idx[0]]
              line_num = selected_project.get("line_num", 1)
              live.stop()
              subprocess.run([config.editor, f"+{line_num}", str(config.projects_file)])
              projects = get_project_list(config)
              proj_idx[0] = min(proj_idx[0], max(0, len(projects) - 1))
              live.start()
          elif key == "a":
            if projects:
              selected_project = projects[proj_idx[0]]
              move_project_to_section(config.projects_file,
                                      selected_project["slug"], "Archived")
              projects = get_project_list(config)
              proj_idx[0] = min(proj_idx[0], max(0, len(projects) - 1))
          elif key == "n":
            if projects:
              selected_project = projects[proj_idx[0]]
              project_dir = config.projects_dir / selected_project["slug"]
              project_md = project_dir / "Project.md"

              live.stop()

              if not project_md.exists():
                project_dir.mkdir(parents=True, exist_ok=True)
                title = selected_project["slug"].replace("-", " ").title()
                project_md.write_text(f"# {title}\n\n\n\n## Tasks\n1. [ ] \n")
                subprocess.run([config.editor, "+6", str(project_md)])
                new_num = 1
              else:
                new_num, line_num = add_task_to_project(project_md)
                if new_num and line_num:
                  subprocess.run([config.editor, f"+{line_num}", str(project_md)])

              if new_num:
                new_tasks = parse_tasks(config, project_md, selected_project["slug"], "")
                task_desc = new_tasks.get(new_num, {}).get("desc", "")
                if task_desc:
                  activate_task(config, selected_project["slug"], new_num, task_desc)

                tasks = get_all_active_tasks(config)

                view[0] = 'task'
                for i, t in enumerate(visible_tasks()):
                  if t["project_slug"] == selected_project["slug"] and t["task_num"] == new_num:
                    task_idx[0] = i
                    break

              live.start()

        live.update(current_display(), refresh=True)

    except KeyboardInterrupt:
      pass
