const doFetch = require('@ntlab/sfetch')
const axios = require('axios')
const dayjs = require('dayjs')
const crypto = require('crypto')
const sortBy = require('lodash.sortby')

// API Configuration Constants
const NATCO_CODE = 'hr'
const APP_LANGUAGE = 'hr'
const APP_KEY = 'GWaBW4RTloLwpUgYVzOiW5zUxFLmoMj5'
const APP_VERSION = '02.0.1470'
const NATCO_KEY = 'l2lyvGVbUm2EKJE96ImQgcc8PKMZWtbE'
const SITE_URL = 'mojmaxtv.hrvatskitelekom.hr'

// Role Types
const ROLE_TYPES = {
  ACTOR: 'GLUMI',      // Croatian for "ACTS"
  DIRECTOR: 'REŽIJA',  // Croatian for "DIRECTOR"
  PRODUCER: 'PRODUKCIJA', // Croatian for "PRODUCER"
  WRITER: 'AUTOR',
  SCENARIO: 'SCENARIJ'
}

// Dynamic API Endpoint based on NATCO_CODE
const API_ENDPOINT = `https://tv-${NATCO_CODE}-prod.yo-digital.com/${NATCO_CODE}-bifrost`

// Session/Device IDs
const DEVICE_ID = crypto.randomUUID()
const SESSION_ID = crypto.randomUUID()

const cached = {}

module.exports = {
  site: SITE_URL,
  url({ date }) {
    return `${API_ENDPOINT}/epg/channel/schedules?date=${date.format(
      'YYYY-MM-DD'
    )}&hour_offset=0&hour_range=3&channelMap_id=&filler=true&app_language=${APP_LANGUAGE}&natco_code=${NATCO_CODE}`
  },
  request: {
    headers: getHeaders(),
    cache: {
      ttl: 24 * 60 * 60 * 1000 // 1 day
    }
  },
  async parser({ content, channel, date }) {
    const data = parseData(content)
    if (!data) return []

    let items = parseItems(data, channel)
    if (!items.length) return []

    const queue = [3, 6, 9, 12, 15, 18, 21]
      .map(offset => {
        const url = module.exports.url({ date }).replace('hour_offset=0', `hour_offset=${offset}`)
        const params = { ...module.exports.request, headers: getHeaders() }

        if (cached[url]) {
          items = items.concat(parseItems(cached[url], channel))
          return null
        }

        return { url, params }
      })
      .filter(Boolean)

    await doFetch(queue, (_req, _data) => {
      if (_data) {
        cached[_req.url] = _data
        items = items.concat(parseItems(_data, channel))
      }
    })

    items = sortBy(items, i => dayjs(i.start_time).valueOf())

    // Fetch program details for each item
    const programs = []
    const queues = items
      .filter(item => item.program_id)
      .map(item => ({
        url: `${API_ENDPOINT}/details/series/${item.program_id}?natco_code=${NATCO_CODE}`,
        params: {
          headers: getHeaders()
        },
        item
      }))
    await doFetch(queues, (queue, res) => {
      queue.item.detail = res
    })
    items.forEach(item => {
      const detail = item.detail || {}
      programs.push({
        title: item.description,
        sub_title: item.episode_name,
        description: parseDescription(detail),
        categories: Array.isArray(item.genres) ? item.genres.map(g => g.name) : [],
        date: parseDate(item),
        image: detail.poster_image_url,
        actors: parseRoles(detail, ROLE_TYPES.ACTOR),
        directors: parseRoles(detail, ROLE_TYPES.DIRECTOR),
        producers: parseRoles(detail, ROLE_TYPES.PRODUCER),
        season: parseSeason(item),
        episode: parseEpisode(item),
        rating: parseRating(item),
        start: item.start_time,
        stop: item.end_time
      })
    })

    return programs
  },
  async channels() {
    const data = await axios
      .get(
        `${API_ENDPOINT}/epg/channel?channelMap_id=&includeVirtualChannels=false&natco_key=${NATCO_KEY}&app_language=${APP_LANGUAGE}&natco_code=${NATCO_CODE}`,
        { ...module.exports.request, headers: getHeaders() }
      )
      .then(r => r.data)
      .catch(console.error)

    return data.channels.map(channel => ({
      lang: NATCO_CODE,
      name: channel.title,
      site_id: channel.station_id
    }))
  }
}

function parseData(content) {
  try {
    const data = JSON.parse(content)
    return data || null
  } catch {
    return null
  }
}

function parseItems(data, channel) {
  if (!data.channels || !Array.isArray(data.channels[channel.site_id])) return []
  return data.channels[channel.site_id]
}

function parseDate(item) {
  return item && item.release_year ? item.release_year.toString() : null
}

function parseRating(item) {
  return item.ratings
    ? {
        system: 'MPA',
        value: item.ratings
      }
    : null
}

function parseSeason(item) {
  if (item.season_display_number === 'Epizode') return null // 'Epizode' is 'Episodes' in Croatian
  return item.season_number
}

function parseEpisode(item) {
  if (item.episode_number) return parseInt(item.episode_number)
  if (item.season_display_number === 'Epizode') return item.season_number
  return null
}

function parseDescription(item) {
  if (!item.details) return null
  return item.details.description
}

function parseRoles(item, role_name) {
  if (!item.roles) return null
  return item.roles.filter(role => role.role_name === role_name).map(role => role.person_name)
}

function getHeaders() {
  const res = {
    'app_key': APP_KEY,
    'app_version': APP_VERSION,
    'device-id': DEVICE_ID,
    'tenant': 'tv',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36',
    'origin': `https://${SITE_URL}`,
    'x-call-type': 'GUEST_USER',
    'x-call-time': new Date().getTime(),
    'x-request-session-id': SESSION_ID,
    'x-request-tracking-id': crypto.randomUUID(),
    'x-tv-step': 'EPG_SCHEDULES',
    'x-tv-flow': 'EPG',
    'x-txn-id': null,
    'x-user-agent': `web|web|Chrome-149|${APP_VERSION}|1`
  }
  const hash = crypto.createHash('sha256')
  hash.update([
    res['x-request-tracking-id'],
    res['x-request-session-id'],
    res['device-id'],
    res['x-call-time']
  ].join(''))
  res['x-txn-id'] = hash.digest('hex').substr(0, 32)

  return res
}
