import { contentLoader } from './ContentLoader.js';
import { questEngine } from './QuestEngine.js';
import { saveState } from './SaveState.js';
import { ticketService } from './TicketService.js';

function normalizeText(value) {
  return String(value ?? '').trim().toLowerCase();
}

function includesAny(text, needles) {
  return needles.some((needle) => text.includes(needle));
}

export class SageService {
  constructor({
    loader = contentLoader,
    quests = questEngine,
    save = saveState,
    tickets = ticketService
  } = {}) {
    this.loader = loader;
    this.quests = quests;
    this.save = save;
    this.tickets = tickets;
  }

  reply(message) {
    const text = normalizeText(message);
    const activeQuest = this._getPrimaryActiveQuest();

    if (!activeQuest) {
      return {
        response: "Nothing urgent is active right now. Check your tickets or mail and ask again once you've got something assigned.",
        followUps: ['Show my open tickets', 'What docs do I have access to?']
      };
    }

    if (!text) {
      return this._buildQuestIntro(activeQuest);
    }

    if (includesAny(text, ['ticket', 'task', 'what am i doing', 'what should i do'])) {
      return this._buildTicketSummary(activeQuest);
    }

    if (includesAny(text, ['vm', 'server', 'host', 'machine'])) {
      return this._buildVmSummary(activeQuest);
    }

    if (includesAny(text, ['doc', 'runbook', 'guide', 'manual'])) {
      return this._buildDocSummary(activeQuest);
    }

    if (includesAny(text, ['help', 'hint', 'stuck', 'clue', 'what now'])) {
      return this._buildHint(activeQuest);
    }

    if (includesAny(text, ['summary', 'recap', 'remind'])) {
      return this._buildQuestIntro(activeQuest);
    }

    return {
      response: "I can help with the active quest, but I'm not improvising answers yet. Ask for a hint, a summary, the target VM, or which docs are relevant.",
      followUps: ['Give me a hint', 'Summarize the task', 'Which VM am I working on?']
    };
  }

  _buildQuestIntro(quest) {
    const intro = this._findDialogueMessage(quest.id, ['intro', 'welcome', 'setup']);
    return {
      response: intro ?? quest.summary ?? quest.description ?? `You're working on ${quest.id}.`,
      followUps: ['Give me a hint', 'Summarize the task', 'Which VM am I working on?']
    };
  }

  _buildTicketSummary(quest) {
    const ticket = quest.ticket_id ? this.loader.get('tickets', quest.ticket_id) : null;
    if (!ticket) {
      return this._buildQuestIntro(quest);
    }

    return {
      response: `${ticket.id}: ${ticket.subject}\n\n${ticket.body}`,
      followUps: ['Give me a hint', 'Which VM am I working on?', 'Which docs are relevant?']
    };
  }

  _buildVmSummary(quest) {
    const ticket = quest.ticket_id ? this.loader.get('tickets', quest.ticket_id) : null;
    const targetVm = ticket?.target_vm ?? 'workstation';
    const profile = this.loader.get('vmProfiles', targetVm);
    const hostname = profile?.hostname ?? targetVm;
    const distro = profile?.distro ?? 'unknown distro';

    return {
      response: `The current target is ${targetVm} (${hostname}). It is authored as ${distro}. Start there unless the ticket explicitly says otherwise.`,
      followUps: ['Give me a hint', 'Summarize the task', 'Which docs are relevant?']
    };
  }

  _buildDocSummary(quest) {
    const unlockedDocs = new Set(this.save.get()?.progression?.unlocked_docs ?? []);
    const docs = [...this.loader.docs.values()]
      .filter((doc) => unlockedDocs.has(doc.id))
      .filter((doc) => this._docLooksRelevant(doc, quest))
      .map((doc) => doc.title);

    return {
      response: docs.length > 0
        ? `Relevant unlocked docs:\n- ${docs.join('\n- ')}`
        : 'You do not currently have an obviously relevant unlocked doc for this quest. Ask for a hint instead.',
      followUps: ['Give me a hint', 'Which VM am I working on?', 'Summarize the task']
    };
  }

  _buildHint(quest) {
    const sageState = this.save.get()?.sage ?? {};
    const nextHintIndex = Number(sageState.hint_counts?.[quest.id] ?? 0) + 1;
    const stageCandidates = [`hint_${nextHintIndex}`, `hint_${nextHintIndex - 1}`, 'hint_1'];
    let hint = null;
    let usedIndex = nextHintIndex;

    for (const stage of stageCandidates) {
      hint = this._findDialogueMessage(quest.id, [stage]);
      if (hint) {
        const match = stage.match(/^hint_(\d+)$/);
        usedIndex = Number(match?.[1] ?? 1);
        break;
      }
    }

    if (!hint) {
      hint = "There isn't another authored hint for this quest yet. Check the ticket body, the target VM, and any unlocked runbooks.";
      usedIndex = Math.max(1, nextHintIndex);
    }

    const nextHints = {
      ...(sageState.hint_counts ?? {}),
      [quest.id]: usedIndex
    };
    this.save.set({
      sage: {
        ...(sageState ?? {}),
        hint_counts: nextHints
      }
    });

    return {
      response: hint,
      followUps: ['Another hint', 'Summarize the task', 'Which docs are relevant?']
    };
  }

  _getPrimaryActiveQuest() {
    const active = this.quests.getAllEntries()
      .filter(([, entry]) => entry?.state === 'active')
      .sort(([, left], [, right]) => {
        const leftTs = Date.parse(left?.started_at ?? '') || 0;
        const rightTs = Date.parse(right?.started_at ?? '') || 0;
        return rightTs - leftTs;
      });

    if (active.length === 0) {
      return null;
    }

    return this.loader.get('quests', active[0][0]) ?? null;
  }

  _findDialogueMessage(questId, preferredStages) {
    const dialogues = [...this.loader.dialogue.values()]
      .filter((dialogue) => dialogue.quest_id === questId);

    for (const stage of preferredStages) {
      for (const dialogue of dialogues) {
        const message = dialogue.messages?.find((entry) => entry.stage === stage);
        if (message?.body) {
          return message.body;
        }
      }
    }

    return null;
  }

  _docLooksRelevant(doc, quest) {
    const text = `${doc.id} ${doc.title} ${doc.body}`.toLowerCase();
    const ticket = quest.ticket_id ? this.loader.get('tickets', quest.ticket_id) : null;
    const vm = ticket?.target_vm ?? '';
    const tags = ticket?.tags ?? [];

    return [quest.id.toLowerCase(), vm, ...tags].some((needle) => needle && text.includes(String(needle).toLowerCase()));
  }
}

export const sageService = new SageService();
