import { eventBus } from '../lib/eventBus.js';
import { toArray } from '../lib/utils.js';
import { contentLoader } from './ContentLoader.js';
import { emailService } from './EmailService.js';
import { saveState } from './SaveState.js';
import { ticketService } from './TicketService.js';

function clone(value) {
  return JSON.parse(JSON.stringify(value));
}

function safeDurationSeconds(startedAt, endedAt) {
  const start = new Date(startedAt ?? 0).getTime();
  const end = new Date(endedAt ?? 0).getTime();
  if (!Number.isFinite(start) || !Number.isFinite(end) || end < start) {
    return null;
  }

  return Math.floor((end - start) / 1000);
}

export class ShiftReviewService {
  constructor({
    bus = eventBus,
    loader = contentLoader,
    email = emailService,
    save = saveState,
    tickets = ticketService,
    now = () => Date.now()
  } = {}) {
    this.bus = bus;
    this.loader = loader;
    this.email = email;
    this.save = save;
    this.tickets = tickets;
    this.now = now;
    this._handlersBound = false;
    this._onTicketActivated = this._handleTicketActivated.bind(this);
    this._onTicketCompleted = this._handleTicketCompleted.bind(this);
    this._onShiftEnded = this._handleShiftEnded.bind(this);
  }

  initialize(state = this.save.get()) {
    this._ensureContainers(state);
    this._seedAssignedTickets(state);
    this._bindHandlers();
  }

  dispose() {
    if (!this._handlersBound) {
      return;
    }

    this.bus.off('ticket:activated', this._onTicketActivated);
    this.bus.off('ticket:completed', this._onTicketCompleted);
    this.bus.off('shift:ended', this._onShiftEnded);
    this._handlersBound = false;
  }

  _bindHandlers() {
    this.dispose();
    this.bus.on('ticket:activated', this._onTicketActivated);
    this.bus.on('ticket:completed', this._onTicketCompleted);
    this.bus.on('shift:ended', this._onShiftEnded);
    this._handlersBound = true;
  }

  _ensureContainers(state = this.save.get()) {
    const nextState = {};

    if (!state?.current_shift_stats) {
      nextState.current_shift_stats = {
        assigned_ticket_ids: [],
        resolved_tickets: [],
        flagged_issues: []
      };
    }

    if (!Array.isArray(state?.shift_history)) {
      nextState.shift_history = [];
    }

    if (Object.keys(nextState).length > 0) {
      this.save.set(nextState);
    }
  }

  _seedAssignedTickets(state = this.save.get()) {
    const stats = state?.current_shift_stats ?? {};
    if (toArray(stats.assigned_ticket_ids).length > 0) {
      return;
    }

    const assignedTicketIds = this.tickets.getAll()
      .filter((ticket) => ticket.status !== 'resolved')
      .map((ticket) => ticket.id);

    if (assignedTicketIds.length > 0) {
      this.save.set({
        current_shift_stats: {
          ...stats,
          assigned_ticket_ids: assignedTicketIds
        }
      });
    }
  }

  _handleTicketActivated({ ticketId }) {
    const state = this.save.get();
    const stats = clone(state?.current_shift_stats ?? {});
    const assigned = new Set(toArray(stats.assigned_ticket_ids));
    assigned.add(ticketId);

    this.save.set({
      current_shift_stats: {
        ...stats,
        assigned_ticket_ids: [...assigned]
      }
    });
  }

  _handleTicketCompleted(payload) {
    const state = this.save.get();
    const stats = clone(state?.current_shift_stats ?? {});
    const resolved = toArray(stats.resolved_tickets);
    const existing = resolved.find((entry) => entry.ticket_id === payload.ticketId);
    const nextResolved = existing
      ? resolved.map((entry) => entry.ticket_id === payload.ticketId ? { ...entry, ...payload } : entry)
      : [...resolved, {
        ticket_id: payload.ticketId,
        branch_id: payload.branchId ?? null,
        trust_delta: Number(payload.trustDelta) || 0,
        activated_at: payload.activatedAt ?? null,
        resolved_at: payload.resolvedAt ?? new Date(this.now()).toISOString()
      }];

    const flaggedIssues = [...toArray(stats.flagged_issues)];
    if (Number(payload.trustDelta) <= 0) {
      flaggedIssues.push({
        ticket_id: payload.ticketId,
        type: 'wrong_approach',
        detail: payload.branchId
          ? `${payload.ticketId} resolved with ${payload.branchId}`
          : `${payload.ticketId} resolved with a risky branch`
      });
    }

    this.save.set({
      current_shift_stats: {
        ...stats,
        resolved_tickets: nextResolved,
        flagged_issues: flaggedIssues
      }
    });
  }

  _handleShiftEnded(snapshot) {
    const state = this.save.get();
    const stats = clone(state?.current_shift_stats ?? {});
    const assigned = toArray(stats.assigned_ticket_ids);
    const resolved = toArray(stats.resolved_tickets);
    const resolvedIds = new Set(resolved.map((entry) => entry.ticket_id));
    const timedOutIds = assigned.filter((ticketId) => !resolvedIds.has(ticketId));

    const flaggedIssues = [
      ...toArray(stats.flagged_issues),
      ...timedOutIds.map((ticketId) => ({
        ticket_id: ticketId,
        type: 'timed_out',
        detail: `${ticketId} rolled into the next shift unresolved`
      }))
    ];

    const durations = resolved
      .map((entry) => safeDurationSeconds(entry.activated_at, entry.resolved_at))
      .filter((value) => Number.isInteger(value));

    const averageResolutionSeconds = durations.length > 0
      ? Math.round(durations.reduce((sum, value) => sum + value, 0) / durations.length)
      : null;

    const review = {
      shift_number: state?.shift_number ?? 1,
      started_at: state?.shift_started_at ?? snapshot?.startedAt ?? new Date(this.now()).toISOString(),
      ended_at: new Date(this.now()).toISOString(),
      tickets_assigned: assigned.length,
      tickets_resolved: resolved.length,
      average_resolution_seconds: averageResolutionSeconds,
      flagged_issues: flaggedIssues,
      performance_tier: this._performanceTier({
        assignedCount: assigned.length,
        resolvedCount: resolved.length,
        flaggedIssueCount: flaggedIssues.length
      }),
      reviewer: 'Priya Nair'
    };

    const reviewSentence = this._reviewSentence(review.performance_tier);
    const reviewBody = [
      `Shift ${review.shift_number} performance review`,
      '',
      `Tickets resolved: ${review.tickets_resolved}/${review.tickets_assigned}`,
      `Average resolution time: ${this._formatDuration(review.average_resolution_seconds)}`,
      `Flagged issues: ${flaggedIssues.length === 0 ? 'none' : flaggedIssues.map((issue) => issue.detail).join('; ')}`,
      '',
      reviewSentence
    ].join('\n');

    const nextShiftNumber = review.shift_number + 1;
    const nextShiftStartedAt = new Date(this.now()).toISOString();

    this.save.set({
      shift_number: nextShiftNumber,
      shift_started_at: nextShiftStartedAt,
      shift_history: [...toArray(state?.shift_history), review],
      current_shift_stats: {
        assigned_ticket_ids: this.tickets.getAll()
          .filter((ticket) => ticket.status !== 'resolved')
          .map((ticket) => ticket.id),
        resolved_tickets: [],
        flagged_issues: []
      }
    });

    this.email.send({
      id: `mail-shift-review-${review.shift_number}-${Date.now()}`,
      from: 'Priya Nair <p.nair@axiomworks.internal>',
      subject: `Shift ${review.shift_number} review`,
      body: reviewBody,
      attachments: [],
      replyOptions: []
    });
  }

  _performanceTier({ assignedCount, resolvedCount, flaggedIssueCount }) {
    if (assignedCount > 0 && resolvedCount === assignedCount && flaggedIssueCount === 0) {
      return 'excellent';
    }

    if (resolvedCount > 0 && flaggedIssueCount <= 1) {
      return 'ok';
    }

    return 'poor';
  }

  _reviewSentence(tier) {
    const dialogue = this.loader.get('dialogue', 'priya-shift-review');
    const message = toArray(dialogue?.messages).find((entry) => entry.stage === tier);
    return message?.body ?? 'Shift closed.';
  }

  _formatDuration(value) {
    if (!Number.isInteger(value) || value < 0) {
      return 'n/a';
    }

    const minutes = Math.floor(value / 60);
    const seconds = value % 60;
    return `${minutes}m ${String(seconds).padStart(2, '0')}s`;
  }
}

export const shiftReviewService = new ShiftReviewService();
