const cheerio = require('cheerio')
const axios = require('axios')
const dayjs = require('dayjs')
const customParseFormat = require('dayjs/plugin/customParseFormat')
const utc = require('dayjs/plugin/utc')
const timezone = require('dayjs/plugin/timezone')
require('dayjs/locale/fr')

dayjs.extend(customParseFormat)
dayjs.extend(utc)
dayjs.extend(timezone)

const PARIS_TZ = 'Europe/Paris'

module.exports = {
  site: 'guidetnt.com',
  days: 2,
  url({ channel, date }) {
    const now = dayjs()
    const demain = now.add(1, 'd')
    if (date && date.isSame(demain, 'day')) {
      return `https://www.guidetnt.com/tv-demain/programme-${channel.site_id}`
    } else if (!date || date.isSame(now, 'day')) {
      return `https://www.guidetnt.com/tv/programme-${channel.site_id}`
    } else {
      return null
    }
  },
  async parser({ content, date }) {
    const programs = []
    const allItems = parseItems(content)
    const items = allItems?.rows
    const itemDate = allItems?.formattedDate
    for (const item of items) {
      const prev = programs[programs.length - 1]
      const $item = cheerio.load(item)
      const title = parseTitle($item)
      let start = parseStart($item, itemDate)

      if (!start || !title) return
      if (prev) {
        if (start.isBefore(prev.start)) {
          start = start.add(1, 'd')
          date = date.add(1, 'd')
        }
        prev.stop = start
      }
      let stop = start.add(30, 'm')

      let itemDetails = null
      let subTitle = null
      //let duration = null
      let country = null
      let productionDate = null
      let episode = null
      let season = null
      let category = parseCategory($item)
      let description = parseDescription($item)
      const itemDetailsURL = parseDescriptionURL($item)
      if (itemDetailsURL) {
        const url = 'https://www.guidetnt.com' + itemDetailsURL
        try {
          const response = await axios.get(url)
          itemDetails = parseItemDetails(response.data)
        } catch (err) {
          console.error(`Erreur lors du fetch des détails pour l'item: ${url}`, err)
        }

        const timeRange = parseTimeRange(itemDetails?.programHour, date.format('YYYY-MM-DD'))
        start = timeRange?.start
        stop = timeRange?.stop

        subTitle = itemDetails?.subTitle
        if (title == subTitle) subTitle = null
        description = itemDetails?.description

        const categoryDetails = parseCategoryText(itemDetails?.category)
        //duration = categoryDetails?.duration
        country = categoryDetails?.country
        productionDate = categoryDetails?.productionDate
        season = categoryDetails?.season
        episode = categoryDetails?.episode
      }
      // See https://www.npmjs.com/package/epg-parser for parameters
      programs.push({
        title,
        subTitle: subTitle,
        description: description,
        image: itemDetails?.image,
        category: category,
        directors: itemDetails?.directorActors?.Réalisateur,
        actors: itemDetails?.directorActors?.Acteur,
        country: country,
        date: productionDate,
        //duration: duration, // Tried with length: too, but does not work ! (stop-start is not accurate because of Ads)
        season: season,
        episode: episode,
        start,
        stop
      })
    }

    return programs
  },
  async channels() {
    const response = await axios.get('https://www.guidetnt.com')
    const channels = []
    const $ = cheerio.load(response.data)

    // Look inside each .tvlogo container
    $('.tvlogo').each((i, el) => {
      // Find all descendants that have an alt attribute
      $(el)
        .find('[alt]')
        .each((j, subEl) => {
          const alt = $(subEl).attr('alt')
          const href = $(subEl).attr('href')
          if (href && alt && alt.trim() !== '') {
            const name = alt.trim()
            const site_id = href.replace(/^\/tv\/programme-/, '')
            channels.push({
              lang: 'fr',
              name,
              site_id
            })
          }
        })
    })
    return channels
  }
}

function parseTimeRange(timeRange, baseDate) {
  // Split times
  const [startStr, endStr] = timeRange.split(' - ').map(s => s.trim())

  // Parse with base date
  const start = dayjs(`${baseDate} ${startStr}`, 'YYYY-MM-DD HH:mm')
  let end = dayjs(`${baseDate} ${endStr}`, 'YYYY-MM-DD HH:mm')

  // Handle possible day wrap (e.g., 23:30 - 00:15)
  if (end.isBefore(start)) {
    end = end.add(1, 'day')
  }

  // Calculate duration in minutes
  const diffMinutes = end.diff(start, 'minute')

  return {
    start: start.format(),
    stop: end.format(),
    duration: diffMinutes
  }
}

function parseItemDetails(itemDetails) {
  const $ = cheerio.load(itemDetails)

  const program = $('.program-wrapper').first()

  const programHour = program.find('.program-hour').text().trim()
  const programTitle = program.find('.program-title').text().trim()
  const programElementBold = program.find('.program-element-bold').text().trim()
  const programArea1 = program.find('.program-element.program-area-1').text().trim()

  let description = ''
  const programElements = $('.program-element').filter((i, el) => {
    const classAttr = $(el).attr('class')
    // Return true only if it is exactly "program-element" (no extra classes)
    return classAttr.trim() === 'program-element'
  })

  programElements.each((i, el) => {
    description += $(el).text().trim()
  })

  const area2Node = $('.program-area-2').first()
  const area2 = $(area2Node)
  const data = {}
  let currentLabel = null
  let texts = []

  area2.contents().each((i, node) => {
    if (node.type === 'tag' && node.name === 'strong') {
      // If we had collected some text for the previous label, save it
      if (currentLabel && texts.length) {
        data[currentLabel] = texts.join('').trim().replace(/,\s*$/, '') // Remove trailing comma
      }
      // New label - get text without colon
      currentLabel = $(node).text().replace(/:$/, '').trim()
      texts = []
    } else if (currentLabel) {
      // Append the text content (text node or others)
      if (node.type === 'text') {
        texts.push(node.data)
      } else if (node.type === 'tag' && node.name !== 'strong' && node.name !== 'br') {
        texts.push($(node).text())
      }
    }
  })

  // Save last label text
  if (currentLabel && texts.length) {
    data[currentLabel] = texts.join('').trim().replace(/,\s*$/, '')
  }

  const imgSrc = program.find('div[style*="float:left"]')?.find('img')?.attr('src') || null

  return {
    programHour,
    title: programTitle,
    subTitle: programElementBold,
    category: programArea1,
    description: description,
    directorActors: data,
    image: imgSrc
  }
}

function parseCategoryText(text) {
  if (!text) return null

  const parts = text
    .split(',')
    .map(s => s.trim())
    .filter(Boolean)
  const len = parts.length

  const category = parts[0] || null

  if (len < 3) {
    return {
      category: category,
      duration: null,
      country: null,
      productionDate: null,
      season: null,
      episode: null
    }
  }

  // Check last part: date if numeric
  const dateCandidate = parts[len - 1]
  const productionDate = /^\d{4}$/.test(dateCandidate) ? dateCandidate : null

  // Check for duration (first part containing "minutes")
  let durationMinute = null
  //let duration = null
  let episode = null
  let season = null
  let durationIndex = -1
  for (let i = 0; i < len; i++) {
    if (parts[i].toLowerCase().includes('minute')) {
      durationMinute = parts[i].trim()
      durationMinute = durationMinute.replace('minutes', '')
      durationMinute = durationMinute.replace('minute', '')
      //duration = [{ units: 'minutes', value: durationMinute }],
      durationIndex = i
    } else if (parts[i].toLowerCase().includes('épisode')) {
      const match = text.match(/épisode\s+(\d+)(?:\/(\d+))?/i)
      if (match) {
        episode = parseInt(match[1], 10)
      }
    } else if (parts[i].toLowerCase().includes('saison')) {
      season = parts[i].replace('saison', '').trim()
    }
  }

  // Country: second to last
  const countryIndex = len - 2
  let country = durationIndex === countryIndex ? null : parts[countryIndex]

  return {
    category,
    durationMinute,
    country,
    productionDate,
    season,
    episode
  }
}

function parseTitle($item) {
  return $item('.channel-programs-title a').text().trim()
}

function parseDescription($item) {
  return $item('#descr').text().trim() || null
}

function parseDescriptionURL($item) {
  const descrLink = $item('#descr a')
  return descrLink.attr('href') || null
}

function parseCategory($item) {
  let type = null
  $item('.channel-programs-title span').each((i, span) => {
    const className = $item(span).attr('class')
    if (className && className.startsWith('text_bg')) {
      type = $item(span).text().trim()
    }
  })
  return type
}

function parseStart($item, itemDate) {
  const dt = $item('.channel-programs-time a').text().trim()
  if (!dt) return null

  const datetimeStr = `${itemDate} ${dt}`
  return dayjs.tz(datetimeStr, 'YYYY-MM-DD HH:mm', PARIS_TZ)
}

function parseItems(content) {
  const $ = cheerio.load(content)

  // Extract header information
  const logoSrc = $('#logo img').attr('src')
  const title = $('#title h1').text().trim()
  const subtitle = $('#subtitle').text().trim()
  const dateMatch = subtitle.match(/(\d{1,2} \w+ \d{4})/)
  const dateStr = dateMatch ? dateMatch[1].toLowerCase() : null

  // Parse the French date string
  const parsedDate = dayjs(dateStr, 'D MMMM YYYY', 'fr')
  // Format it as YYYY-MM-DD
  const formattedDate = parsedDate.format('YYYY-MM-DD')

  const rows = $('.channel-row').toArray()

  return {
    rows,
    logoSrc,
    title,
    formattedDate
  }
}
