import type { Message } from 'node-telegram-bot-api'
import type { ApplyOptions, ApplyResult, ResumeListItem, VacancyRef } from './types.js'
import type { StatusReporter } from './ui.js'
import bot from '@bot'
import prisma from '@prisma'
import { createMessage } from '../openai'
import { getBrowser, loadSession, randomDelay } from './browser.js'

function waitForOtp(chatId: number): Promise<string> {
  return new Promise((resolve) => {
    const handler = (msg: Message) => {
      if (msg.chat.id !== chatId || !msg.text)
        return
      bot.removeListener('message', handler)
      resolve(msg.text)
    }
    bot.on('message', handler)
  })
}

export async function login(email: string, chatId: number): Promise<void> {
  const browser = await getBrowser()
  // await bot.sendMessage(chatId, `Browser is connected: ${browser.isConnected()}`)
  if (!browser.version()) {
    console.log('browser error')
    return
  }

  const context = await browser.newContext()
  const page = await context.newPage()

  await page.goto('https://hh.ru/account/login', { waitUntil: 'networkidle' })
  await bot.sendMessage(chatId, `page: ${page.url()}`)

  await page.click('[data-qa="submit-button"]')
  await page.waitForTimeout(randomDelay())
  // await bot.sendMessage(chatId, `Клик по "Войти"`)

  await page.click('label:has([data-qa="credential-type-EMAIL"])')
  await page.waitForTimeout(randomDelay())
  // await bot.sendMessage(chatId, `Клик по "Email"`)

  await page.fill('[data-qa="applicant-login-input-email"]', email)
  await page.waitForTimeout(randomDelay())
  // await bot.sendMessage(chatId, `Ввод "Email"`)

  await page.click('[data-qa="submit-button"]')
  // await bot.sendMessage(chatId, `Клик по "Дальше"`)
  await page.waitForTimeout(randomDelay())

  await bot.sendMessage(chatId, '🔑 Введи код из email')
  await page.waitForTimeout(randomDelay())

  await page.click('[data-qa="applicant-login-input-otp"]')
  const otp = await waitForOtp(chatId)
  await page.fill('[data-qa="applicant-login-input-otp"] input', otp)
  // await bot.sendMessage(chatId, `Введён ОТП: ${otp}`)

  await page.waitForTimeout(randomDelay())
  await page.waitForLoadState('networkidle')

  const cookies = await context.cookies()
  await prisma.user.update({
    where: { telegramId: chatId },
    data: { session: JSON.stringify(cookies, null, 2) },
  })

  await bot.sendMessage(chatId, cookies.length > 0 ? '✅ Авторизация выполнена' : '❌ Произошла ошибка')
  await browser.close()
}

export async function checkIsAuth(telegramId: bigint | number) {
  const browser = await getBrowser()
  const context = await browser.newContext()
  const page = await context.newPage()
  await loadSession(page, telegramId)
  await page.goto('https://hh.ru/search/vacancy', { waitUntil: 'networkidle' })
  try {
    return await page.$('[data-qa="profileAndResumes-button"]')
  }
  catch (e) {
    return e
  }
}

export async function listResumes(chatId: number): Promise<ResumeListItem[]> {
  const browser = await getBrowser()
  const context = await browser.newContext()
  const page = await context.newPage()
  await loadSession(page, chatId)
  await page.goto('https://hh.ru/applicant/resumes', { waitUntil: 'networkidle' })

  const resumes = await page.$$eval(
    '[data-qa^="resume-card-link-"]',
    links => links.map(a => ({
      href: (a as HTMLAnchorElement).getAttribute('href') ?? '',
      title: a.textContent?.trim() ?? '(без названия)',
    })),
  )

  await browser.close()
  return resumes
}

export async function saveResume(chatId: number, resumeHref: string): Promise<string | undefined> {
  const browser = await getBrowser()
  const context = await browser.newContext()
  const page = await context.newPage()
  await loadSession(page, chatId)

  const id = new URL(`https://hh.ru${resumeHref}`).pathname.split('/').pop()!
  const resumeUrl = `https://hh.ru/resume_converter/resume.txt?hash=${id}&type=txt&hhtmFrom=&hhtmSource=resume`

  await page.goto(resumeUrl, { waitUntil: 'networkidle' })

  let resume: string | undefined
  try {
    resume = await page.locator('.resume').innerText()
    await prisma.resume.upsert({
      where: { id },
      create: { data: resume, id, telegramId: chatId },
      update: { data: resume },
    })
  }
  catch (e) {
    console.log(e)
    await bot.sendMessage(chatId, 'Нет резюме на hh.ru, создайте')
  }
  finally {
    await browser.close()
  }

  return resume
}

export async function applyToJobs(
  { query, area = 1, maxApplies = 10 }: ApplyOptions,
  { chatId, reporter }: { chatId: number, reporter: StatusReporter },
): Promise<ApplyResult> {
  const browser = await getBrowser()
  const context = await browser.newContext()
  const page = await context.newPage()
  const results: ApplyResult = { applied: [], skipped: [], errors: [] }
  const { status, keep, clear } = reporter

  try {
    await loadSession(page, chatId)

    const url = `https://hh.ru/search/vacancy?text=${encodeURIComponent(query)}&area=${area}`
    await page.goto(url, { waitUntil: 'networkidle' })

    if (!await page.$('[data-qa="profileAndResumes-button"]')) {
      return { ...results, error: 'Не авторизован. Выполните login' }
    }

    await status('✅ Авторизация выполнена')

    const vacancies = await page.$$eval(
      '[data-qa="serp-item__title"]',
      links => links.map(a => ({
        href: (a as HTMLAnchorElement).href,
        title: a.textContent?.trim() ?? '',
      })),
    )

    await status(`✅ Вакансий найдено: ${vacancies.length}`)

    const resume = await prisma.resume.findFirst({ where: { telegramId: chatId } })
    const user = await prisma.user.findUnique({ where: { telegramId: chatId } })

    if (!resume?.data) {
      await keep('❌ Резюме не выбрано — выбери резюме через меню')
      return results
    }

    for (const vacancy of vacancies.slice(0, maxApplies)) {
      const ref: VacancyRef = { title: vacancy.title, href: vacancy.href }
      try {
        await status(`🔄 Обрабатывается: ${vacancy.title}`)
        await page.goto(vacancy.href, { waitUntil: 'networkidle' })

        const description = await page
          .locator('[data-qa="vacancy-description"]')
          .innerText()
          .catch(() => '')

        if (!description) {
          results.skipped.push(ref)
          continue
        }

        await status(`✍️ Генерирую письмо: ${vacancy.title}`)

        const letter = await createMessage(resume.data, description, user!.prompt)
        await keep(`✅ <b>${vacancy.title}</b>\n\n${letter}`)

        results.applied.push(ref)
      }
      catch (err) {
        results.errors.push({ ...ref, message: (err as Error).message })
      }
    }

    await clear()
  }
  finally {
    await browser.close()
  }

  return results
}
