import { eventBus } from '../lib/eventBus.js';
import { createError } from '../lib/utils.js';
import { contentLoader } from './ContentLoader.js';
import { emailService } from './EmailService.js';
import { questEngine } from './QuestEngine.js';
import { saveState } from './SaveState.js';
import { trustSystem } from './TrustSystem.js';
import { validationEngine } from './ValidationEngine.js';
import { behaviorTracker } from './BehaviorTracker.js';

class TicketService {
  constructor() {
    this._tickets = new Map();
  }

  initialize(state) {
    this._tickets = new Map();

    for (const [ticketId, entry] of Object.entries(state.tickets ?? {})) {
      const ticket = contentLoader.get('tickets', ticketId);
      if (!ticket) {
        continue;
      }

      const questState = ticket.linked_quest ? questEngine.getState(ticket.linked_quest) : 'locked';
      if (!['active', 'completed', 'failed'].includes(questState)) {
        continue;
      }

      this._tickets.set(ticketId, this._normalizeEntry(entry));
    }

    for (const [questId, entry] of questEngine.getAllEntries()) {
      if (entry?.state === 'active') {
        const quest = contentLoader.get('quests', questId);
        if (quest?.ticket_id) {
          this.activateTicket(quest.ticket_id);
        }
      }

      if (entry?.state === 'completed') {
        const quest = contentLoader.get('quests', questId);
        if (quest?.ticket_id) {
          const ticketEntry = this._tickets.get(quest.ticket_id);
          if (!ticketEntry || ticketEntry.status !== 'resolved') {
            this._tickets.set(quest.ticket_id, {
              status: 'resolved',
              activated_at: ticketEntry?.activated_at ?? entry.started_at ?? null,
              resolved_at: ticketEntry?.resolved_at ?? entry.completed_at ?? null
            });
          }
        }
      }
    }

    this._persist();
  }

  getAll() {
    return [...this._tickets.entries()]
      .filter(([ticketId]) => this._isPrimaryTicketId(ticketId))
      .sort(([leftId], [rightId]) => leftId.localeCompare(rightId))
      .map(([ticketId, entry]) => {
        const ticket = contentLoader.get('tickets', ticketId);
        if (!ticket) {
          return null;
        }

        return {
          id: ticket.id,
          subject: ticket.subject,
          priority: entry.current_priority ?? ticket.current_priority,
          status: entry.status ?? 'open',
          linked_quest: ticket.linked_quest
        };
      })
      .filter(Boolean);
  }

  getEntry(ticketId) {
    const entry = this._tickets.get(ticketId);
    if (!entry) {
      return null;
    }

    return { ...entry };
  }

  activateTicket(ticketId) {
    const ticket = contentLoader.get('tickets', ticketId);
    if (!ticket) {
      throw createError(`Unknown ticket: ${ticketId}`, 404);
    }

    const existing = this._tickets.get(ticketId);
    if (existing) {
      return existing.status;
    }

    this._tickets.set(ticketId, {
      status: 'open',
      current_priority: ticket.current_priority,
      activated_at: new Date().toISOString(),
      resolved_at: null
    });
    this._persist();
    eventBus.emit('ticket:activated', { ticketId });
    return 'open';
  }

  getDetail(ticketId) {
    const ticket = contentLoader.get('tickets', ticketId);
    const entry = this._tickets.get(ticketId);

    if (!ticket || !entry) {
      return null;
    }

    return {
      ...ticket,
      status: entry.status ?? 'open',
      activated_at: entry.activated_at ?? null,
      resolved_at: entry.resolved_at ?? null
    };
  }

  setStatus(ticketId, status) {
    const ticket = contentLoader.get('tickets', ticketId);
    if (!ticket) {
      throw createError(`Unknown ticket: ${ticketId}`, 404);
    }

    const existing = this._tickets.get(ticketId) ?? this._defaultEntry(ticket);
    const nextEntry = {
      ...existing,
      status
    };

    if (status === 'resolved' && !nextEntry.resolved_at) {
      nextEntry.resolved_at = new Date().toISOString();
    }

    this._tickets.set(ticketId, nextEntry);
    this._persist();
  }

  setPriority(ticketId, priority) {
    const ticket = contentLoader.get('tickets', ticketId);
    if (!ticket) {
      throw createError(`Unknown ticket: ${ticketId}`, 404);
    }

    const existing = this._tickets.get(ticketId) ?? this._defaultEntry(ticket);
    this._tickets.set(ticketId, {
      ...existing,
      current_priority: priority
    });
    this._persist();
  }

  async markComplete(ticketId, options = {}) {
    const ticket = contentLoader.get('tickets', ticketId);
    if (!ticket) {
      return { passed: false, reason: 'ticket_not_found' };
    }

    const ticketEntry = this._tickets.get(ticketId);
    if (!ticketEntry) {
      return { passed: false, reason: 'ticket_not_active' };
    }

    if (ticketEntry.status === 'resolved') {
      return {
        passed: true,
        branch: ticketEntry.branch_id ?? null,
        trust_delta: 0,
        failures: [],
        ticket_status: 'resolved',
        already_resolved: true
      };
    }

    const quest = ticket.linked_quest ? contentLoader.get('quests', ticket.linked_quest) : null;
    if (!quest) {
      return { passed: false, reason: 'quest_not_found' };
    }

    if (!questEngine.isActive(quest.id)) {
      if (!questEngine.canActivate(quest.id)) {
        return { passed: false, reason: 'quest_locked' };
      }

      questEngine.activate(quest.id);
    }

    let branch = null;
    let failures = [];

    if (options.branchId) {
      branch = this._selectBranch(quest, options.branchId);
      if (!branch) {
        return { passed: false, reason: 'branch_not_found' };
      }
    } else {
      const validationResult = await validationEngine.resolveBranch(quest);
      branch = validationResult.branch;
      failures = validationResult.failures;
      if (!branch) {
        return {
          passed: false,
          reason: 'validation_failed',
          failures
        };
      }
    }

    const appliedFlags = this._appendWorldFlags(branch.world_flags ?? []);
    const trustDelta = Number(branch.trust_delta) || 0;

    if (trustDelta !== 0) {
      trustSystem.adjust(trustDelta);
    }

    questEngine.complete(quest.id, { branchId: branch.id });

    const behaviorImpact = branch.behavior_impact
      ?? quest.behavior_impact?.[branch.id]
      ?? quest.behavior_impact?.default
      ?? null;
    if (behaviorImpact && typeof behaviorImpact === 'object') {
      behaviorTracker.apply(behaviorImpact);
    }

    const nextEntry = {
      ...ticketEntry,
      status: 'resolved',
      resolved_at: new Date().toISOString(),
      branch_id: branch.id
    };
    this._tickets.set(ticketId, nextEntry);

    const followUpTicketId = this._activateFollowUpTicket(branch.follow_up_ticket ?? null);
    const followUpMailIds = [];

    if (trustDelta <= 0) {
      for (const dialogueId of this._collectFollowUpDialogues(branch)) {
        const mail = emailService.sendDialogueFollowUp(dialogueId, {
          questId: quest.id,
          ticketId: ticket.id,
          subjectPrefix: `Follow-up on ${ticket.id}`,
          idPrefix: `mail-${ticket.id}`
        });
        if (mail?.id) {
          followUpMailIds.push(mail.id);
        }
      }
    }

    this._persist();
    eventBus.emit('ticket:completed', {
      ticketId,
      questId: quest.id,
      branchId: branch.id,
      trustDelta,
      activatedAt: nextEntry.activated_at ?? ticketEntry.activated_at ?? null,
      resolvedAt: nextEntry.resolved_at
    });

    return {
      passed: true,
      branch: branch.id,
      trust_delta: trustDelta,
      failures: [],
      ticket_status: 'resolved',
      world_flags: appliedFlags,
      follow_up_ticket: followUpTicketId,
      follow_up_mail_ids: followUpMailIds
    };
  }

  _persist() {
    saveState.set({ tickets: Object.fromEntries(this._tickets) });
  }

  _selectBranch(quest, branchId) {
    const branches = [...(quest.solution_branches ?? [])].sort((left, right) => (right.priority ?? 0) - (left.priority ?? 0));
    if (branchId) {
      return branches.find((branch) => branch.id === branchId) ?? null;
    }

    return branches[0] ?? null;
  }

  _appendWorldFlags(flags) {
    const state = saveState.get();
    const nextFlags = new Set(state?.world_flags ?? []);

    for (const flag of flags) {
      nextFlags.add(flag);
    }

    const snapshot = [...nextFlags];
    saveState.set({ world_flags: snapshot });
    return snapshot;
  }

  _activateFollowUpTicket(ticketId) {
    if (!ticketId) {
      return null;
    }

    const ticket = contentLoader.get('tickets', ticketId);
    if (!ticket) {
      return null;
    }

    const questId = ticket.linked_quest;
    if (questId && !questEngine.isCompleted(questId) && questEngine.canActivate(questId)) {
      questEngine.activate(questId);
    }

    this.activateTicket(ticketId);
    return ticketId;
  }

  _collectFollowUpDialogues(branch) {
    const ids = [];

    if (branch.follow_up_dialogue) {
      ids.push(branch.follow_up_dialogue);
    }

    for (const id of branch.follow_up_dialogues ?? []) {
      ids.push(id);
    }

    return ids;
  }

  _normalizeEntry(entry) {
    if (typeof entry === 'string') {
      return {
        status: entry,
        current_priority: null,
        activated_at: null,
        resolved_at: null,
        branch_id: null
      };
    }

    return {
      status: entry?.status ?? 'open',
      current_priority: entry?.current_priority ?? null,
      activated_at: entry?.activated_at ?? null,
      resolved_at: entry?.resolved_at ?? null,
      branch_id: entry?.branch_id ?? null
    };
  }

  _defaultEntry(ticket) {
    return {
      status: 'open',
      current_priority: ticket.current_priority,
      activated_at: new Date().toISOString(),
      resolved_at: null,
      branch_id: null
    };
  }

  _isPrimaryTicketId(ticketId) {
    return /^T\d{3}$/.test(ticketId);
  }
}

export const ticketService = new TicketService();
