import { getDb } from '../db/client.js'
import { publish } from '../plugins/valkey.js'
import { sendToSessionParticipant } from '../plugins/websocket.js'
import { extendSessionTimer, clearClosureGraceTimer, startClosureGraceTimer } from './session-timer.service.js'
import { UserType, SessionStatus, ExtensionStatus, TransactionType, WsMessage } from '../constants.js'

const sql = getDb()

// Extension timeout map: extensionId → timeoutId
const extensionTimeouts = new Map()

const getExtensionTimeout = async () => {
  const [row] = await sql`SELECT value FROM app_config WHERE key = 'extension_timeout_seconds'`
  return (row?.value?.value ?? 60) * 1000 // Convert to ms
}

export const requestExtension = async (sessionId, customerId, { duration_minutes, price }) => {
  // Verify session belongs to customer and is in an extendable state
  const [session] = await sql`
    SELECT id, customer_id, mitra_id, status, topic_sensitivity FROM chat_sessions
    WHERE id = ${sessionId} AND customer_id = ${customerId}
      AND status IN (${SessionStatus.ACTIVE}, ${SessionStatus.CLOSING})
  `
  if (!session) {
    throw Object.assign(new Error('Session not found or already ended'), { code: 'SESSION_NOT_ACTIVE', statusCode: 409 })
  }

  // Create extension record
  const [extension] = await sql`
    INSERT INTO session_extensions (session_id, requested_duration_minutes, requested_price, status)
    VALUES (${sessionId}, ${duration_minutes}, ${price}, ${ExtensionStatus.PENDING})
    RETURNING id, session_id, requested_duration_minutes, requested_price, status, requested_at
  `

  // Pause the session
  await sql`UPDATE chat_sessions SET status = ${SessionStatus.EXTENDING} WHERE id = ${sessionId}`

  // Notify mitra — include current topic sensitivity so UI can highlight
  sendToSessionParticipant(sessionId, UserType.MITRA, {
    type: WsMessage.EXTENSION_REQUEST,
    extension_id: extension.id,
    session_id: sessionId,
    duration_minutes,
    price,
    topic_sensitivity: session.topic_sensitivity,
  })

  // Notify customer that chat is paused
  sendToSessionParticipant(sessionId, UserType.CUSTOMER, {
    type: WsMessage.SESSION_PAUSED,
    session_id: sessionId,
    reason: 'extension_pending',
  })

  // Start timeout
  const timeoutMs = await getExtensionTimeout()
  const timeoutId = setTimeout(async () => {
    try {
      await timeoutExtension(extension.id, sessionId)
    } catch (_) {}
  }, timeoutMs)
  extensionTimeouts.set(extension.id, timeoutId)

  return extension
}

export const respondToExtension = async (extensionId, sessionId, mitraId, accepted) => {
  // Verify session belongs to this mitra
  const [session] = await sql`
    SELECT id FROM chat_sessions WHERE id = ${sessionId} AND mitra_id = ${mitraId}
  `
  if (!session) {
    throw Object.assign(new Error('Session not found'), { code: 'FORBIDDEN', statusCode: 403 })
  }

  const status = accepted ? ExtensionStatus.ACCEPTED : ExtensionStatus.REJECTED

  const [extension] = await sql`
    UPDATE session_extensions
    SET status = ${status}, responded_at = NOW()
    WHERE id = ${extensionId} AND session_id = ${sessionId} AND status = ${ExtensionStatus.PENDING}
    RETURNING id, session_id, requested_duration_minutes, requested_price, status
  `

  if (!extension) {
    throw Object.assign(new Error('Extension not found or already resolved'), {
      code: 'EXTENSION_RESOLVED', statusCode: 409,
    })
  }

  // Clear timeout
  const timeoutId = extensionTimeouts.get(extensionId)
  if (timeoutId) {
    clearTimeout(timeoutId)
    extensionTimeouts.delete(extensionId)
  }

  if (accepted) {
    // Clear any pending grace timer from the previous expiry
    clearClosureGraceTimer(sessionId)

    // Extend the session
    await extendSessionTimer(extension.session_id, extension.requested_duration_minutes)

    // Resume session
    await sql`UPDATE chat_sessions SET status = ${SessionStatus.ACTIVE} WHERE id = ${extension.session_id}`

    // Record transaction
    await sql`
      INSERT INTO customer_transactions (customer_id, session_id, type, amount)
      SELECT customer_id, id, ${TransactionType.EXTENSION}, ${extension.requested_price}
      FROM chat_sessions WHERE id = ${extension.session_id}
    `

    // Notify both parties
    sendToSessionParticipant(sessionId, UserType.CUSTOMER, {
      type: WsMessage.EXTENSION_RESPONSE,
      accepted: true,
      duration_minutes: extension.requested_duration_minutes,
    })
    sendToSessionParticipant(sessionId, UserType.CUSTOMER, {
      type: WsMessage.SESSION_RESUMED,
      session_id: sessionId,
    })
    sendToSessionParticipant(sessionId, UserType.MITRA, {
      type: WsMessage.SESSION_RESUMED,
      session_id: sessionId,
    })
  } else {
    // Rejected — proceed to closure
    await sql`UPDATE chat_sessions SET status = ${SessionStatus.CLOSING} WHERE id = ${extension.session_id}`

    sendToSessionParticipant(sessionId, UserType.CUSTOMER, {
      type: WsMessage.EXTENSION_RESPONSE,
      accepted: false,
    })
    sendToSessionParticipant(sessionId, UserType.MITRA, {
      type: WsMessage.SESSION_CLOSING,
      session_id: sessionId,
    })
    sendToSessionParticipant(sessionId, UserType.CUSTOMER, {
      type: WsMessage.SESSION_CLOSING,
      session_id: sessionId,
    })
    startClosureGraceTimer(sessionId)
  }

  return extension
}

const timeoutExtension = async (extensionId, sessionId) => {
  extensionTimeouts.delete(extensionId)

  const [extension] = await sql`
    UPDATE session_extensions
    SET status = ${ExtensionStatus.TIMEOUT}, responded_at = NOW()
    WHERE id = ${extensionId} AND status = ${ExtensionStatus.PENDING}
    RETURNING id, session_id
  `
  if (!extension) return

  // Timeout = proceed to closure
  await sql`UPDATE chat_sessions SET status = ${SessionStatus.CLOSING} WHERE id = ${extension.session_id}`

  sendToSessionParticipant(sessionId, UserType.CUSTOMER, {
    type: WsMessage.EXTENSION_RESPONSE,
    accepted: false,
    reason: 'timeout',
  })
  sendToSessionParticipant(sessionId, UserType.MITRA, {
    type: WsMessage.SESSION_CLOSING,
    session_id: sessionId,
  })
  sendToSessionParticipant(sessionId, UserType.CUSTOMER, {
    type: WsMessage.SESSION_CLOSING,
    session_id: sessionId,
  })
  startClosureGraceTimer(sessionId)
}
