import { authenticate } from '../../plugins/auth.js'
import { getCustomerById } from '../../services/customer.service.js'
import {
  createPairingRequest,
  createTargetedPairingRequest,
  cancelPairingRequest,
  cancelPaymentSearch,
  fallbackToGeneralBlast,
} from '../../services/pairing.service.js'
import {
  getActiveSessionByCustomer,
  getActiveSessionByCustomerWithUnread,
  endSession,
  getCustomerHistory,
} from '../../services/session.service.js'
import { getPricingForCustomer } from '../../services/pricing.service.js'
import { requestExtension } from '../../services/extension.service.js'
import { EndedBy, TopicSensitivity, UserType } from '../../constants.js'

const resolveCustomer = async (request, reply) => {
  if (request.auth?.userType !== UserType.CUSTOMER) {
    return reply.code(403).send({
      success: false,
      error: { code: 'FORBIDDEN', message: 'Customer account required' },
    })
  }
  const customer = await getCustomerById(request.auth.userId)
  if (!customer) {
    return reply.code(404).send({
      success: false,
      error: { code: 'ACCOUNT_NOT_FOUND', message: 'Customer account not found' },
    })
  }
  request.customer = customer
}

export const clientChatRoutes = async (app) => {
  // Get chat + call pricing tiers + first-session-discount eligibility (per-customer).
  // Phase 4 reshape — tiers come from `app_config.pricing_{chat,call}_tiers_json` and
  // discount eligibility is the AND of: phone-verified + no completed sessions +
  // first_session_discount_enabled.
  app.get('/pricing', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const pricing = await getPricingForCustomer(request.customer.id)
    return reply.send({ success: true, data: pricing })
  })

  /**
   * Start a general-blast pairing search.
   *
   * Body MUST include `payment_session_id` (a confirmed payment_session owned by the caller).
   * Pricing/duration/free-trial values are sourced from the payment session, NOT from the client.
   */
  app.post('/request', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const { payment_session_id, topic_sensitivity } = request.body ?? {}

    if (!payment_session_id) {
      return reply.code(400).send({
        success: false,
        error: { code: 'BAD_REQUEST', message: 'payment_session_id is required' },
      })
    }

    if (topic_sensitivity !== TopicSensitivity.REGULAR && topic_sensitivity !== TopicSensitivity.SENSITIVE) {
      return reply.code(400).send({
        success: false,
        error: { code: 'BAD_REQUEST', message: 'topic_sensitivity must be regular or sensitive' },
      })
    }

    const session = await createPairingRequest(request.customer.id, {
      paymentSessionId: payment_session_id,
      topic_sensitivity,
    })
    return reply.code(201).send({ success: true, data: session })
  })

  /**
   * Start a targeted "Curhat lagi" pairing request.
   *
   * Body: { payment_session_id, mitra_id, topic_sensitivity? }
   * Returns 409 with reason: 'targeted_mitra_offline' if the targeted mitra is unreachable
   * or at capacity. The payment session stays `confirmed` in that case so the customer
   * can fall back to general blast on the same payment.
   */
  app.post('/chat-requests/returning', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const { payment_session_id, mitra_id, topic_sensitivity } = request.body ?? {}

    if (!payment_session_id) {
      return reply.code(400).send({
        success: false,
        error: { code: 'BAD_REQUEST', message: 'payment_session_id is required' },
      })
    }
    if (!mitra_id) {
      return reply.code(400).send({
        success: false,
        error: { code: 'BAD_REQUEST', message: 'mitra_id is required' },
      })
    }

    const resolvedTopic = (topic_sensitivity === TopicSensitivity.SENSITIVE)
      ? TopicSensitivity.SENSITIVE
      : TopicSensitivity.REGULAR

    const session = await createTargetedPairingRequest(request.customer.id, {
      paymentSessionId: payment_session_id,
      targetedMitraId: mitra_id,
      topic_sensitivity: resolvedTopic,
    })
    return reply.code(201).send({ success: true, data: session })
  })

  /**
   * Customer-initiated cancel during searching/waiting.
   *
   * Body: { payment_session_id }
   * Terminal — payment session moves to failed_pairing with cause = customer_cancelled.
   */
  app.post('/chat-requests/cancel', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const { payment_session_id } = request.body ?? {}
    if (!payment_session_id) {
      return reply.code(400).send({
        success: false,
        error: { code: 'BAD_REQUEST', message: 'payment_session_id is required' },
      })
    }
    const result = await cancelPaymentSearch(payment_session_id, request.customer.id)
    return reply.send({ success: true, data: result })
  })

  /**
   * After a returning-chat fail, customer taps "Chat dengan bestie lain".
   * Reuses the same payment_session_id (no double-charge), runs general blast.
   */
  app.post('/chat-requests/:paymentSessionId/fallback-to-blast', {
    preHandler: [authenticate, resolveCustomer],
  }, async (request, reply) => {
    const { topic_sensitivity } = request.body ?? {}
    const resolvedTopic = (topic_sensitivity === TopicSensitivity.SENSITIVE)
      ? TopicSensitivity.SENSITIVE
      : TopicSensitivity.REGULAR
    const session = await fallbackToGeneralBlast(
      request.params.paymentSessionId,
      request.customer.id,
      { topic_sensitivity: resolvedTopic },
    )
    return reply.code(201).send({ success: true, data: session })
  })

  /**
   * Cancel-by-session-id retained for in-flight chat_session cancels (e.g. cancel
   * during the 20s targeted wait after a chat_session has been created). Customer cancel
   * via payment_session_id should prefer POST /chat-requests/cancel above.
   */
  app.post('/request/:sessionId/cancel', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const session = await cancelPairingRequest(request.params.sessionId, request.customer.id)
    return reply.send({ success: true, data: session })
  })

  app.get('/session/active', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const session = await getActiveSessionByCustomer(request.customer.id)
    return reply.send({ success: true, data: session ?? null })
  })

  app.get('/session/active-with-unread', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const session = await getActiveSessionByCustomerWithUnread(request.customer.id)
    return reply.send({ success: true, data: session ?? null })
  })

  app.post('/session/:sessionId/end', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const session = await endSession(request.params.sessionId, EndedBy.CUSTOMER, request.customer.id)
    return reply.send({ success: true, data: session })
  })

  /**
   * Extension request REQUIRES `extension_payment_session_id`.
   * The payment session must be is_extension=true and is_first_session_discount=false.
   * Pricing/duration come from the payment session via the extension service.
   */
  app.post('/session/:sessionId/extend', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const { duration_minutes, price, extension_payment_session_id } = request.body ?? {}

    if (!extension_payment_session_id) {
      return reply.code(400).send({
        success: false,
        error: { code: 'BAD_REQUEST', message: 'extension_payment_session_id is required' },
      })
    }
    if (!duration_minutes || price === undefined) {
      return reply.code(400).send({
        success: false,
        error: { code: 'BAD_REQUEST', message: 'duration_minutes and price are required' },
      })
    }

    const extension = await requestExtension(request.params.sessionId, request.customer.id, {
      duration_minutes,
      price,
      extension_payment_session_id,
    })
    return reply.send({ success: true, data: extension })
  })

  // Phase 4 Stage 10 — Chat Tab Selesai feed. Cursor-paginated; old `page`
  // param removed. Response shape: { items, next_cursor, has_more }.
  app.get('/history', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const { cursor, limit } = request.query
    const history = await getCustomerHistory(request.customer.id, {
      cursor: cursor ?? null,
      limit: limit ? parseInt(limit, 10) : 20,
    })
    return reply.send({ success: true, data: history })
  })
}
