import { authenticate } from '../../plugins/auth.js'
import { getCustomerById } from '../../services/customer.service.js'
import {
  createPaymentSession,
  confirmPaymentSession,
  abandonPaymentSession,
  getPaymentSession,
  getCustomerPendingPayments,
} from '../../services/payment.service.js'
import {
  isCustomerEligibleForFirstSessionDiscount,
  isValidTier,
  findTier,
} from '../../services/pricing.service.js'
import { getDb } from '../../db/client.js'
import { UserType, SessionMode } from '../../constants.js'

const sql = getDb()

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
}

const readDiscountConfig = async () => {
  const rows = await sql`
    SELECT key, value FROM app_config
    WHERE key IN (
      'first_session_discount_enabled',
      'first_session_discount_actual_price_idr',
      'first_session_discount_duration_minutes',
      'first_session_discount_modes'
    )
  `
  const byKey = Object.fromEntries(rows.map((r) => [r.key, r.value?.value]))
  return {
    enabled: byKey.first_session_discount_enabled ?? true,
    actual_price_idr: byKey.first_session_discount_actual_price_idr ?? 2000,
    duration_minutes: byKey.first_session_discount_duration_minutes ?? 12,
    modes: byKey.first_session_discount_modes ?? ['chat'],
  }
}

/**
 * Payment session lifecycle (mocked — no Xendit yet).
 *
 *   POST   /api/client/payment-sessions
 *   POST   /api/client/payment-sessions/:id/confirm
 *   POST   /api/client/payment-sessions/:id/cancel
 *   GET    /api/client/payment-sessions/:id
 */
export const clientPaymentRoutes = async (app) => {
  // Create a payment session (status = pending). First-session-discount is server-authoritative:
  // if the customer is eligible AND this is NOT an extension AND mode is in the configured
  // modes list, amount is forced to the configured discount price.
  app.post('/', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const {
      duration_minutes,
      mode = SessionMode.CHAT,
      targeted_mitra_id = null,
      is_extension = false,
    } = request.body ?? {}

    if (typeof duration_minutes !== 'number' || duration_minutes <= 0) {
      return reply.code(422).send({
        success: false,
        error: { code: 'VALIDATION_ERROR', message: 'duration_minutes must be a positive number' },
      })
    }
    if (mode !== SessionMode.CHAT && mode !== SessionMode.CALL) {
      return reply.code(422).send({
        success: false,
        error: { code: 'VALIDATION_ERROR', message: 'mode must be chat or call' },
      })
    }

    let isFirstSessionDiscount = false
    let amount

    if (!is_extension) {
      const eligible = await isCustomerEligibleForFirstSessionDiscount(request.customer.id)
      if (eligible) {
        const discount = await readDiscountConfig()
        // Discount is mode-gated. With default config (modes: ['chat']) call-mode never
        // gets the discount even if the user is eligible.
        if (
          discount.enabled
          && discount.modes.includes(mode)
          && duration_minutes === discount.duration_minutes
        ) {
          isFirstSessionDiscount = true
          amount = discount.actual_price_idr
        }
      }
    }

    if (!isFirstSessionDiscount) {
      // Resolve amount from the configured tier list for the requested mode.
      const tier = await findTier({ mode, durationMinutes: duration_minutes })
      if (!tier) {
        return reply.code(400).send({
          success: false,
          error: { code: 'INVALID_TIER', message: 'No price tier matches the requested mode/duration' },
        })
      }
      amount = tier.price_idr
      if (!(await isValidTier({ mode, durationMinutes: duration_minutes, priceIdr: amount }))) {
        return reply.code(400).send({
          success: false,
          error: { code: 'INVALID_TIER', message: 'Invalid price tier selection' },
        })
      }
    }

    const session = await createPaymentSession({
      customerId: request.customer.id,
      durationMinutes: duration_minutes,
      amount,
      isFirstSessionDiscount,
      isExtension: Boolean(is_extension),
      targetedMitraId: targeted_mitra_id || null,
      mode,
    })

    return reply.code(201).send({
      success: true,
      data: {
        id: session.id,
        amount: session.amount,
        duration_minutes: session.duration_minutes,
        is_first_session_discount: session.is_first_session_discount,
        is_extension: session.is_extension,
        mode: session.mode,
        targeted_mitra_id: session.targeted_mitra_id,
        expires_at: session.expires_at,
        status: session.status,
      },
    })
  })

  app.post('/:id/confirm', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const session = await confirmPaymentSession(request.params.id, request.customer.id)
    return reply.send({
      success: true,
      data: {
        id: session.id,
        status: session.status,
        confirmed_at: session.confirmed_at,
      },
    })
  })

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

  // Phase 4 Stage 10 — Chat Tab Pembayaran feed. Static path; registered
  // before `/:id` so find-my-way matches this and not the wildcard.
  app.get('/pending', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const data = await getCustomerPendingPayments(request.customer.id)
    return reply.send({ success: true, data })
  })

  app.get('/:id', { preHandler: [authenticate, resolveCustomer] }, async (request, reply) => {
    const session = await getPaymentSession(request.params.id)
    if (!session) {
      return reply.code(404).send({
        success: false,
        error: { code: 'NOT_FOUND', message: 'Payment session not found' },
      })
    }
    if (session.customer_id !== request.customer.id) {
      return reply.code(403).send({
        success: false,
        error: { code: 'FORBIDDEN', message: 'Payment session does not belong to this customer' },
      })
    }
    return reply.send({ success: true, data: session })
  })
}
