import { getDb } from '../db/client.js'
import { sendToSessionParticipant } from '../plugins/websocket.js'
import { getSensitivityConfig } from './config.service.js'
import { SessionStatus, TopicSensitivity, UserType, WsMessage } from '../constants.js'

const sql = getDb()

const FLIPPABLE_STATUSES = [SessionStatus.ACTIVE, SessionStatus.EXTENDING]

export const flipSessionSensitivity = async ({ sessionId, mitraId, toValue }) => {
  if (toValue !== TopicSensitivity.REGULAR && toValue !== TopicSensitivity.SENSITIVE) {
    throw Object.assign(new Error('Invalid topic_sensitivity value'), {
      code: 'INVALID_TOPIC', statusCode: 400,
    })
  }

  const [session] = await sql`
    SELECT id, mitra_id, status, topic_sensitivity
    FROM chat_sessions
    WHERE id = ${sessionId}
  `
  if (!session) {
    throw Object.assign(new Error('Session not found'), {
      code: 'SESSION_NOT_FOUND', statusCode: 404,
    })
  }
  if (session.mitra_id !== mitraId) {
    throw Object.assign(new Error('Not allowed'), {
      code: 'FORBIDDEN', statusCode: 403,
    })
  }
  if (!FLIPPABLE_STATUSES.includes(session.status)) {
    throw Object.assign(new Error('Session is not in a flippable state'), {
      code: 'SESSION_NOT_ACTIVE', statusCode: 409,
    })
  }

  const fromValue = session.topic_sensitivity
  if (fromValue === toValue) {
    return { session_id: sessionId, topic_sensitivity: fromValue, changed: false }
  }

  const { one_way_latch } = await getSensitivityConfig()
  if (one_way_latch && fromValue === TopicSensitivity.SENSITIVE && toValue === TopicSensitivity.REGULAR) {
    throw Object.assign(new Error('Sensitive flag is locked and cannot be reverted'), {
      code: 'SENSITIVITY_LATCHED', statusCode: 409,
    })
  }

  const [log] = await sql.begin(async (tx) => {
    await tx`
      UPDATE chat_sessions
      SET topic_sensitivity = ${toValue}
      WHERE id = ${sessionId}
    `
    return tx`
      INSERT INTO session_sensitivity_log (session_id, changed_by_mitra_id, from_value, to_value)
      VALUES (${sessionId}, ${mitraId}, ${fromValue}, ${toValue})
      RETURNING id, created_at
    `
  })

  const payload = {
    type: WsMessage.SESSION_TOPIC_UPDATED,
    session_id: sessionId,
    topic_sensitivity: toValue,
    changed_at: log.created_at,
  }
  sendToSessionParticipant(sessionId, UserType.CUSTOMER, payload)
  sendToSessionParticipant(sessionId, UserType.MITRA, payload)

  return {
    session_id: sessionId,
    topic_sensitivity: toValue,
    changed: true,
    changed_at: log.created_at,
  }
}

export const getSessionSensitivityLog = async (sessionId) => {
  const rows = await sql`
    SELECT l.id, l.session_id, l.changed_by_mitra_id, m.display_name AS changed_by_mitra_name,
      l.from_value, l.to_value, l.created_at
    FROM session_sensitivity_log l
    LEFT JOIN mitras m ON m.id = l.changed_by_mitra_id
    WHERE l.session_id = ${sessionId}
    ORDER BY l.created_at ASC
  `
  return rows
}
