/**
 * Rule-based task extraction from transcripts.
 * Identifies action items from natural speech patterns.
 */

// Action verbs that typically start task sentences
const ACTION_VERBS = [
  "call", "email", "send", "write", "build", "fix", "update", "check",
  "review", "schedule", "book", "create", "set up", "follow up", "organise",
  "prepare", "draft", "submit", "cancel", "confirm", "arrange", "order",
  "buy", "get", "find", "look into", "research", "test", "deploy", "push",
  "move", "add", "remove", "delete", "install", "configure", "contact",
  "message", "tell", "ask", "invite", "remind", "finish", "complete",
  "start", "begin", "plan", "design", "implement", "refactor",
];

// Phrases that signal a task
const TASK_PHRASES = [
  "need to", "needs to", "should", "must", "have to", "has to",
  "want to", "going to", "gonna", "got to", "gotta",
  "don't forget to", "remember to", "make sure to", "make sure we",
  "let's", "we should", "i should", "we need to", "i need to",
  "we have to", "i have to", "we must", "i must",
];

// Explicit markers (user intentionally marks a task)
const EXPLICIT_MARKERS = [
  "action:", "action item:", "todo:", "task:", "to do:",
  "action item", "follow up:", "follow-up:",
];

const SORTED_TASK_PHRASES = [...TASK_PHRASES].sort((a, b) => b.length - a.length);
const LISTABLE_VERBS = ["get", "buy", "pick up", "order"];
const LISTABLE_VERB_PATTERN = new RegExp(`^(${LISTABLE_VERBS.join("|")})\\s+(.+)$`, "i");

/**
 * Extract tasks from a transcript string.
 * Returns an array of { text, confidence } objects.
 */
export function extractTasks(transcript: string): ExtractedTask[] {
  if (!transcript || !transcript.trim()) return [];

  const tasks: ExtractedTask[] = [];
  const seen = new Set<string>();

  // Split into sentences (rough but effective for speech)
  const sentences = splitSentences(transcript);

  for (const sentence of sentences) {
    const trimmed = sentence.trim();
    if (trimmed.length < 5) continue;

    const lower = trimmed.toLowerCase();
    let matched = false;

    // Check explicit markers (highest confidence)
    for (const marker of EXPLICIT_MARKERS) {
      if (lower.startsWith(marker) || lower.includes(marker)) {
        const taskText = extractAfterMarker(trimmed, marker);
        if (taskText && taskText.length > 3) {
          addTask(tasks, seen, capitalise(taskText), 0.95);
          matched = true;
          break;
        }
      }
    }
    if (matched) continue;

    // Check task phrases (high confidence)
    const phraseMatches = findPhraseMatches(lower);
    if (phraseMatches.length > 0) {
      for (let i = 0; i < phraseMatches.length; i += 1) {
        const match = phraseMatches[i];
        const nextMatch = phraseMatches[i + 1] ?? null;
        const taskCandidates = extractTaskCandidatesFromPhrase(trimmed, match, nextMatch);
        for (const candidate of taskCandidates) {
          if (candidate.length > 3) {
            addTask(tasks, seen, capitalise(candidate), 0.8);
            matched = true;
          }
        }
      }
    }
    if (matched) continue;

    // Check if sentence starts with an action verb (medium confidence)
    const firstWord = lower.split(/\s+/)[0];
    const firstTwo = lower.split(/\s+/).slice(0, 2).join(" ");
    if (ACTION_VERBS.includes(firstWord) || ACTION_VERBS.includes(firstTwo)) {
      addTask(tasks, seen, capitalise(trimmed), 0.6);
    }
  }

  return tasks;
}

function splitSentences(text: string): string[] {
  // Split on sentence-ending punctuation, newlines, or common speech breaks
  return text
    .split(/(?<=[.!?])\s+|\n+/)
    .flatMap((s) => s.split(/(?:,\s*(?:and\s+)?)?(?=(?:then|also|plus)\s)/i))
    .filter((s) => s.trim().length > 0);
}

function extractAfterMarker(sentence: string, marker: string): string | null {
  const lower = sentence.toLowerCase();
  const idx = lower.indexOf(marker);
  if (idx < 0) return null;
  const extracted = sentence.slice(idx + marker.length).trim().replace(/^[:\-–—]\s*/, "");
  return cleanTaskText(extracted);
}

function findPhraseMatches(lower: string): PhraseMatch[] {
  const matches: PhraseMatch[] = [];

  for (let i = 0; i < lower.length; i += 1) {
    for (const phrase of SORTED_TASK_PHRASES) {
      if (!lower.startsWith(phrase, i)) continue;
      if (!hasPhraseBoundary(lower, i, phrase.length)) continue;
      matches.push({ index: i, phrase });
      i += phrase.length - 1;
      break;
    }
  }

  return matches;
}

function hasPhraseBoundary(text: string, index: number, length: number): boolean {
  const before = index === 0 ? "" : text[index - 1];
  const after = index + length >= text.length ? "" : text[index + length];
  return isBoundaryChar(before) && isBoundaryChar(after);
}

function isBoundaryChar(char: string): boolean {
  return !char || /[^a-z0-9]/i.test(char);
}

function extractTaskCandidatesFromPhrase(
  sentence: string,
  match: PhraseMatch,
  nextMatch: PhraseMatch | null,
): string[] {
  const end = nextMatch?.index ?? sentence.length;
  const afterPhrase = sentence.slice(match.index + match.phrase.length, end).trim();
  const cleaned = cleanTaskText(afterPhrase);
  if (!cleaned) return [];
  return expandListTask(cleaned);
}

function cleanTaskText(text: string): string {
  return text
    .replace(/^[,;:\-–—\s]+/, "")
    .replace(/\s+/g, " ")
    .replace(/[.!?]+$/, "")
    .trim();
}

function expandListTask(taskText: string): string[] {
  const match = taskText.match(LISTABLE_VERB_PATTERN);
  if (!match) return [taskText];

  const [, verb, remainder] = match;
  if (!/(?:,|&|\band\b)/i.test(remainder)) {
    return [taskText];
  }

  const items = remainder
    .split(/\s*(?:,|&|\band\b)\s*/i)
    .map((item) => cleanTaskText(item))
    .filter(Boolean);

  if (
    items.length < 2
    || items.some((item) => item.split(/\s+/).length > 4)
    || items.some((item) => containsActionLanguage(item))
  ) {
    return [taskText];
  }

  return items.map((item) => `${verb} ${item}`);
}

function containsActionLanguage(text: string): boolean {
  const lower = text.toLowerCase();
  const words = lower.split(/\s+/);
  const firstWord = words[0] ?? "";
  const firstTwo = words.slice(0, 2).join(" ");
  return (
    ACTION_VERBS.includes(firstWord)
    || ACTION_VERBS.includes(firstTwo)
    || TASK_PHRASES.some((phrase) => lower.includes(phrase))
  );
}

function capitalise(text: string): string {
  if (!text) return text;
  // Clean up leading punctuation/whitespace
  const cleaned = text.replace(/^[,;:\-–—\s]+/, "").trim();
  if (!cleaned) return text;
  return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
}

function addTask(
  tasks: ExtractedTask[],
  seen: Set<string>,
  text: string,
  confidence: number,
) {
  // Remove trailing punctuation for dedup
  const key = text.toLowerCase().replace(/[.!?,;:]+$/, "").trim();
  if (seen.has(key)) return;
  seen.add(key);
  tasks.push({ text: text.replace(/[.!?]+$/, "").trim(), confidence });
}
interface ExtractedTask {
  text: string;
  confidence: number;
}

interface PhraseMatch {
  index: number;
  phrase: string;
}
