import "go:fmt"
import "go:strconv"
import "go:strings"
import "go:time"

import "display"
import "models"
import "store"

pub fn add(args: Slice<string>) -> Result<(), string> {
  let Some(title) = args.get(2) else {
    return Err("usage: add <title> [--priority low|medium|high] [--tags a,b,c]")
  }

  let mut priority = models.Priority.Medium
  let mut tags: Slice<string> = []

  let mut i = 3
  while i < args.length() {
    match args[i] {
      "--priority" => {
        let Some(val) = args.get(i + 1) else {
          return Err("--priority requires a value")
        }
        priority = models.parse_priority(val)?
        i += 2
      },
      "--tags" => {
        let Some(val) = args.get(i + 1) else {
          return Err("--tags requires a value")
        }
        tags = strings.Split(val, ",")
        i += 2
      },
      other => return Err(f"unknown flag: '{other}'"),
    }
  }

  let items = store.load()?
  let id = store.next_id(items)
  let item = models.Task.new(id, title, priority, tags)
  let items = items.append(item)
  store.save(items)?

  fmt.Println(f"Added task #{id}: {title} ({priority.label()} priority)")
  Ok(())
}

pub fn done(args: Slice<string>) -> Result<(), string> {
  let Some(id_str) = args.get(2) else {
    return Err("usage: done <id>")
  }
  let id = parse_id(id_str)?

  let items = store.load()?
  let items = store.complete(items, id)?
  store.save(items)?

  fmt.Println(f"Completed task #{id}")
  Ok(())
}

pub fn cancel(args: Slice<string>) -> Result<(), string> {
  let Some(id_str) = args.get(2) else {
    return Err("usage: cancel <id> <reason>")
  }
  let Some(reason) = args.get(3) else {
    return Err("usage: cancel <id> <reason>")
  }
  let id = parse_id(id_str)?

  let items = store.load()?
  let items = store.cancel(items, id, reason)?
  store.save(items)?

  fmt.Println(f"Cancelled task #{id}")
  Ok(())
}

pub fn list() -> Result<(), string> {
  let items = store.load()?
  let pending = items.filter(|t| t.status == models.Status.Pending)
  let done = items.filter(|t| t.status == models.Status.Done)
  let cancelled = items.filter(|t| t.status.is_cancelled())

  display.print_tasks("Pending", pending)
  display.print_tasks("Done", done)
  display.print_tasks("Cancelled", cancelled)
  Ok(())
}

pub fn stats() -> Result<(), string> {
  let items = store.load()?
  display.print_stats(items)
  Ok(())
}

pub fn watch() -> Result<(), string> {
  let ch = Channel.new<bool>()

  task {
    loop {
      time.Sleep(2 * time.Second)
      ch.send(true)
    }
  }

  fmt.Println("Watching tasks (Ctrl+C to stop)...")
  list()?

  for _ in ch {
    fmt.Println("\x1b[2J\x1b[H")
    list()?
  }
  Ok(())
}

fn parse_id(s: string) -> Result<int, string> {
  match strconv.Atoi(s) {
    Ok(id) => Ok(id),
    Err(_) => Err(f"'{s}' is not a valid task ID"),
  }
}
