// eslint-disable-next-line @typescript-eslint/no-unused-vars
import type { NuxtAxiosInstance } from '@nuxtjs/axios'
import { z } from 'zod'
import {
  CreatorSimple,
  DataColors,
  dateToString,
  formatCurrency,
  GraphDataset,
  GraphElement,
} from '~/types'

export {}

export const getDatesUrlQuery = (from: Date, to: Date) =>
  `?from=${from.toISOString().split('T')[0]}&to=${
    to.toISOString().split('T')[0]
  }`

export const DATE_RANGE_ENDPOINT_URL =
  '/dashboard/api/v1/creator/statistics/range'
export const SIMPLE_CREATORS_ENDPOINT_URL = '/dashboard/api/v1/creators'
export const STATISTICS_ALL_CREATORS_ENDPOINT_URL = (from: Date, to: Date) =>
  `/dashboard/api/v1/creator/statistics${getDatesUrlQuery(from, to)}`
export const STATISTICS_SINGLE_CREATOR_ENDPOINT_URL = (
  creatorId: number,
  from: Date,
  to: Date,
) =>
  `/dashboard/api/v1/creator/${creatorId}/statistics${getDatesUrlQuery(
    from,
    to,
  )}`
export const STATISTICS_UPDATE_LINK_CLICKS_ENDPOINT_URL = (creatorId: number) =>
  `/dashboard/api/v1/creator/${creatorId}/statistics/clicks`

// ------------------------------------
// TIKTOK
/**
 * Get all TikTok accounts of a creator
 * @param creatorId
 * @RequestBody interval
 * @RequestBody from
 * @returns TikTok accounts
 */
export const TIKTOK_ACCOUNTS_ENDPOINT_URL = (
  creatorId: number,
  from: Date,
  to: Date,
) =>
  `/dashboard/api/v1/${creatorId}/tiktok/accounts${getDatesUrlQuery(from, to)}`
export const TIKTOK_VIDEOS_ENDPOINT_URL = (
  creatorId: number,
  from: Date,
  to: Date,
  account: string,
  page: number,
) =>
  `/dashboard/api/v1/${creatorId}/tiktok/videos${getDatesUrlQuery(
    from,
    to,
  )}&page=${page}&accountName=${encodeURIComponent(account)}`
export const TIKTOK_COVER_ENDPOINT_URL = (creatorId: number, videoId: string) =>
  `/dashboard/api/v1/${creatorId}/tiktok/cover?tikTokId=${videoId}`

const TikTokAccountSchema = z.object({
  viewDate: z.string(),
  account: z.string(),
  viewsGrowth: z.number().nullish(),
  followersGrowth: z.number().nullish(),
})

export type TikTokAccount = z.infer<typeof TikTokAccountSchema>

const TikTokAccountsResponseSchema = z.object({
  views: z.array(TikTokAccountSchema),
})

export async function listTikTokStats(
  axios: NuxtAxiosInstance,
  creatorId: number,
  from: Date,
  to?: Date,
) {
  const response = await axios.$get(
    TIKTOK_ACCOUNTS_ENDPOINT_URL(creatorId, from, to ?? new Date()),
  )
  const stats = TikTokAccountsResponseSchema.parse(response).views
  const accounts = new Map<string, TikTokAccount>()
  stats
    .map(account => ({ ...account, viewsGrowth: account.viewsGrowth ?? 0 }))
    .sort(
      (a, b) => new Date(a.viewDate).getTime() - new Date(b.viewDate).getTime(),
    )
    .forEach(stat => {
      const current = accounts.get(stat.account)
      if (current) {
        accounts.set(stat.account, {
          account: current.account,
          viewsGrowth: (current.viewsGrowth ?? 0) + (stat.viewsGrowth ?? 0),
          followersGrowth:
            (current.followersGrowth ?? 0) + (stat.followersGrowth ?? 0),
          viewDate: stat.viewDate,
        })
      } else {
        accounts.set(stat.account, stat)
      }
    })
  return [...accounts.values()]
}

const TikTokVideoSchema = z.object({
  id: z.string(),
  title: z.string(),
  accountName: z.string(),
  growth: z.number().nullish(),
  link: z.string(),
})

export type TikTokVideo = z.infer<typeof TikTokVideoSchema>

const TikTokVideosResponseSchema = z.object({
  views: z.array(TikTokVideoSchema),
  total: z.number(),
})

export async function listTikTokVideos(
  axios: NuxtAxiosInstance,
  creatorId: number,
  from: Date,
  to: Date | null,
  account: string,
  page = 1,
) {
  const response = await axios.$get(
    TIKTOK_VIDEOS_ENDPOINT_URL(
      creatorId,
      from,
      to ?? new Date(),
      account,
      page,
    ),
  )
  const result = TikTokVideosResponseSchema.parse(response)
  return Promise.all(
    result.views.map(async post => {
      return await axios
        .$get(TIKTOK_COVER_ENDPOINT_URL(creatorId, post.id), {
          responseType: 'blob',
        })
        .then(cover => {
          const url = window.URL.createObjectURL(cover)
          return {
            ...post,
            cover: url,
          }
        })
        .catch(() => {
          return {
            ...post,
            cover: '/img/error-image-generic.png',
          }
        })
    }),
  )
}

export const getDiffDays = (from: Date, to: Date) => {
  const diff = to.getTime() - from.getTime()
  return Math.ceil(diff / (1000 * 60 * 60 * 24))
}

export class HourLabel {
  hour: number
  label: string

  constructor(hour: number, label: string) {
    this.hour = hour
    this.label = label
  }
}

const hourLabels = [
  new HourLabel(0, '12 AM'),
  new HourLabel(1, '1 AM'),
  new HourLabel(2, '2 AM'),
  new HourLabel(3, '3 AM'),
  new HourLabel(4, '4 AM'),
  new HourLabel(5, '5 AM'),
  new HourLabel(6, '6 AM'),
  new HourLabel(7, '7 AM'),
  new HourLabel(8, '8 AM'),
  new HourLabel(9, '9 AM'),
  new HourLabel(10, '10 AM'),
  new HourLabel(11, '11 AM'),
  new HourLabel(12, '12 PM'),
  new HourLabel(13, '1 PM'),
  new HourLabel(14, '2 PM'),
  new HourLabel(15, '3 PM'),
  new HourLabel(16, '4 PM'),
  new HourLabel(17, '5 PM'),
  new HourLabel(18, '6 PM'),
  new HourLabel(19, '7 PM'),
  new HourLabel(20, '8 PM'),
  new HourLabel(21, '9 PM'),
  new HourLabel(22, '10 PM'),
  new HourLabel(23, '11 PM'),
]

// Populate Labels
export const generateLabels = (from: Date, diffDays: number) => {
  const labels = []

  if (diffDays === 0) {
    return hourLabels.map(hourLabel => hourLabel.label)
  }
  for (let i = 0; i < diffDays + 1; i++) {
    const date = new Date(from)
    date.setDate(date.getDate() + i)
    labels.push(dateToString(date))
  }

  return labels
}

// Populate data with null values
export const generateBlankData = (diffDays: number) => {
  const blankData: (number | null)[] = []
  for (let i = 0; i < diffDays; i++) {
    blankData.push(null)
  }

  return blankData
}

// All Statistic Types
export const STATISTIC_TYPES = [
  new GraphElement(0, 'totalRevenue', 'Total Revenue'),
  new GraphElement(
    1,
    'newSubscriptions',
    'New Subs',
    DataColors.colors[0],
    false,
  ),
  new GraphElement(
    2,
    'messageRevenue',
    'Message Revenue',
    DataColors.colors[4],
  ),
  new GraphElement(
    3,
    'newSubscriptionsRevenue',
    'New Subs Revenue',
    DataColors.colors[1],
  ),
  new GraphElement(
    4,
    'recurringSubscriptionsRevenue',
    'Rec Subs Revenue',
    DataColors.colors[2],
  ),
  // new GraphElement(4, 'totalSubscriptionsRevenue', 'Total Subs Revenue', DataColors.instance.colors[3]),
  new GraphElement(5, 'tipsRevenue', 'Tips Revenue', DataColors.colors[5]),
  new GraphElement(6, 'postsRevenue', 'Posts Revenue', DataColors.colors[6]),
  new GraphElement(7, 'linkClicks', 'Link Clicks', DataColors.colors[7], false),
]

/**
 * @returns {
 *    labels: string[],
 *    datasets: GraphDataset[]
 * } - Returned object needs to be set to this.revenueChart.chartData
 */
export const generateGraphData = (
  multiStatistics: any,
  from: Date,
  to: Date,
  creatorsSimple: CreatorSimple[],
  // TODO: Removee this argument
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  selectedCreators: number[],
  attribute: 'totalRevenue' | 'newSubscriptions' | 'linkClicks',
) => {
  const diffDays = getDiffDays(from, to)
  const labels = generateLabels(from, diffDays)
  const blankData: (number | null)[] = generateBlankData(diffDays)

  const datasets: GraphDataset[] = []

  for (let i = 0; i < multiStatistics.length; i++) {
    const statistics = multiStatistics[i].statistics
    const data = [...blankData]

    if (diffDays > 0) {
      for (let j = 0; j <= diffDays; j++) {
        const date = new Date(from)
        date.setDate(date.getDate() + j)

        if (dateToString(date) in statistics) {
          data[j] =
            parseFloat(statistics[dateToString(date)][attribute] || 0) || 0
        }
      }
    } else {
      const hourlyStatistics = multiStatistics[i].transactions
      for (let j = 0; j < labels.length; j++) {
        const date = new Date(from)
        const label = hourLabels[j]

        if (
          `${dateToString(date)}T${label.hour
            .toString()
            .padStart(2, '0')}:00` in hourlyStatistics
        ) {
          data[label.hour] = Number(
            (
              parseFloat(
                hourlyStatistics[
                  `${dateToString(date)}T${label.hour
                    .toString()
                    .padStart(2, '0')}:00`
                ][attribute] || 0,
              ) || 0
            ).toFixed(2),
          )
        }
      }
    }

    const creator = creatorsSimple.find(
      creator => creator.id === multiStatistics[i].creatorId,
    )

    datasets.push(new GraphDataset(data, creator?.name, creator?.color, false))
  }

  return { labels, datasets }
}

export const generateComposedGraphData = (
  statistics: any,
  from: Date,
  to: Date,
  statisticTypes: GraphElement[],
  selectedStatisticTypes: number[],
) => {
  const diffDays = getDiffDays(from, to)
  const labels = generateLabels(from, diffDays)
  const blankData: (number | null)[] = generateBlankData(diffDays)

  const datasets: GraphDataset[] = []

  for (let i = 0; i < statisticTypes.length; i++) {
    if (
      !statisticTypes[i].moneyRelated ||
      !selectedStatisticTypes.includes(statisticTypes[i].id)
    ) {
      continue
    }

    const data = [...blankData]

    for (let j = 0; j <= diffDays; j++) {
      const date = new Date(from)
      date.setDate(date.getDate() + j)

      if (dateToString(date) in statistics.statistics) {
        data[j] = parseFloat(
          statistics.statistics[dateToString(date)][statisticTypes[i].key] || 0,
        )
      }
    }

    const graphDataset = new GraphDataset(
      data,
      statisticTypes[i].label,
      statisticTypes[i].color,
      false,
    )

    datasets.push(graphDataset)
  }

  return { labels, datasets }
}

export const tableHeaders = [
  '#', // Date or Creator Name
  'Total Revenue',
  'Revenue Growth',
  'New Subs',
  'New Subs Revenue',
  'Rec Subs Revenue',
  'Message Revenue',
  'Tips Revenue',
  'Posts Revenue',
  'Texting Stake',
  'Link Clicks',
  'Conversion Rate',
]

export type StatisticsRow = {
  /**
   * @param {string} position - Date or Creator Name
   */
  position: string
  totalRevenue: string
  growthOfTotalRevenue: string
  newSubs: string
  newSubsRevenue: string
  recSubsRevenue: string
  messageRevenue: string
  tipsRevenue: string
  postsRevenue: string
  textingRevenueStake: string
  linkClicks: string
  conversionRate: string
  openChatCount: string
  sellingChatCount: string
  imgSrc?: string
}

export const generateTableData = (
  singleStatistics: any,
  from: Date,
  to: Date,
  includeChatCount: boolean,
): StatisticsRow[] => {
  const diffDays = getDiffDays(from, to)

  const tableData: StatisticsRow[] = []

  let revenueBefore = singleStatistics[dateToString(from)]?.totalRevenue

  for (let i = 0; i <= diffDays; i++) {
    const date = new Date(from)
    date.setDate(date.getDate() + i)

    const position = dateToString(date)

    const revenue = parseFloat(
      singleStatistics[dateToString(date)]?.totalRevenue || 0,
    )

    const newSubscriptions = parseFloat(
      singleStatistics[dateToString(date)]?.newSubscriptions || 0,
    )

    const newSubscriptionsRevenue = parseFloat(
      singleStatistics[dateToString(date)]?.newSubscriptionsRevenue || 0,
    )

    const recurringSubscriptionsRevenue = parseFloat(
      singleStatistics[dateToString(date)]?.recurringSubscriptionsRevenue || 0,
    )

    const messageRevenue = parseFloat(
      singleStatistics[dateToString(date)]?.messageRevenue || 0,
    )

    const tipsRevenue = parseFloat(
      singleStatistics[dateToString(date)]?.tipsRevenue || 0,
    )

    const postsRevenue = parseFloat(
      singleStatistics[dateToString(date)]?.postsRevenue || 0,
    )

    const linkClicks = parseFloat(
      singleStatistics[dateToString(date)]?.linkClicks || 0,
    )

    const openChatCount = parseFloat(
      singleStatistics[dateToString(date)]?.openChatCount || 0,
    ).toLocaleString()

    const sellingChatCount = parseFloat(
      singleStatistics[dateToString(date)]?.sellingChatCount || 0,
    ).toLocaleString()

    // Calculations

    // Share of texting revenue of total revenue
    const textingRevenueStake =
      revenue > 0 ? (100 / revenue) * messageRevenue : 0

    // const growthOfTotalRevenue =
    //   revenueBefore > 0 ? 100 - (100 / revenueBefore) * revenue : 0
    const growthOfTotalRevenue =
      revenueBefore > 0 ? ((revenue - revenueBefore) / revenueBefore) * 100 : 0

    // Link conversion rate
    const conversionRate =
      linkClicks > 0 ? (100 / linkClicks) * newSubscriptions : 0

    const growthClass =
      growthOfTotalRevenue > 0
        ? 'positive'
        : growthOfTotalRevenue < 0
        ? 'negative'
        : 'neutral'
    const growthString =
      growthOfTotalRevenue > 0 ? '+' : growthOfTotalRevenue < 0 ? '-' : ''
    const growthOfTotalRevenueFormatted = `<span class="turnover-percent--${growthClass}">${growthString}${Math.abs(
      growthOfTotalRevenue,
    ).toFixed(2)}%</span>`

    tableData.push({
      position,
      totalRevenue: formatCurrency(revenue),
      growthOfTotalRevenue: growthOfTotalRevenueFormatted,
      newSubs: newSubscriptions.toString(),
      newSubsRevenue: formatCurrency(newSubscriptionsRevenue),
      recSubsRevenue: formatCurrency(recurringSubscriptionsRevenue),
      messageRevenue: formatCurrency(messageRevenue),
      tipsRevenue: formatCurrency(tipsRevenue),
      postsRevenue: formatCurrency(postsRevenue),
      textingRevenueStake: textingRevenueStake.toFixed(2) + '%',
      linkClicks: linkClicks.toString(),
      conversionRate: conversionRate.toFixed(2) + '%',
      openChatCount: includeChatCount ? openChatCount : 'N/A',
      sellingChatCount: includeChatCount ? sellingChatCount : 'N/A',
    })

    revenueBefore = revenue
  }

  return reverseTableData(tableData)
}

export const reverseTableData = (tableData: StatisticsRow[]) => {
  const reversedTableData: StatisticsRow[] = []

  tableData.forEach(row => {
    reversedTableData.unshift(row)
  })

  return reversedTableData
}

export const generateMultiTableData = (
  multiStatistics: any,
  simpleCreators: CreatorSimple[],
  selectedCreators: number[],
  from: Date,
  to: Date,
  baseUrl: string,
) => {
  const diffDays = getDiffDays(from, to)
  const tableData: StatisticsRow[] = []

  for (let i = 0; i < simpleCreators.length; i++) {
    if (!selectedCreators.includes(simpleCreators[i].id)) continue

    const creator = simpleCreators[i]
    const includeChatCount =
      creator.id === 0 || creator.features.includes('chat_tracking')

    const creatorStats = multiStatistics.find(
      (stat: any) => stat.creatorId === creator.id,
    ).statistics
    const position = creator.name

    let totalRevenue = 0
    let newSubscriptions = 0
    let newSubscriptionsRevenue = 0
    let recurringSubscriptionsRevenue = 0
    let messageRevenue = 0
    let tipsRevenue = 0
    let postsRevenue = 0
    let linkClicks = 0
    let openChatCount = 0
    let sellingChatCount = 0

    for (let j = 0; j <= diffDays; j++) {
      const date = new Date(from)
      date.setDate(date.getDate() + j)

      if (dateToString(date) in creatorStats) {
        totalRevenue +=
          parseFloat(creatorStats[dateToString(date)].totalRevenue || 0) || 0
        newSubscriptions +=
          parseFloat(creatorStats[dateToString(date)].newSubscriptions || 0) ||
          0
        newSubscriptionsRevenue +=
          parseFloat(
            creatorStats[dateToString(date)].newSubscriptionsRevenue || 0,
          ) || 0
        recurringSubscriptionsRevenue +=
          parseFloat(
            creatorStats[dateToString(date)].recurringSubscriptionsRevenue || 0,
          ) || 0
        messageRevenue +=
          parseFloat(creatorStats[dateToString(date)].messageRevenue || 0) || 0
        tipsRevenue +=
          parseFloat(creatorStats[dateToString(date)].tipsRevenue || 0) || 0
        postsRevenue +=
          parseFloat(creatorStats[dateToString(date)].postsRevenue || 0) || 0
        linkClicks +=
          parseFloat(creatorStats[dateToString(date)].linkClicks || 0) || 0
        if (includeChatCount) {
          openChatCount +=
            parseFloat(creatorStats[dateToString(date)].openChatCount || 0) || 0
          sellingChatCount +=
            parseFloat(
              creatorStats[dateToString(date)].sellingChatCount || 0,
            ) || 0
        }
      }
    }

    // Calculations

    // Share of texting revenue of total revenue
    const textingRevenueStake =
      totalRevenue > 0 ? (100 / totalRevenue) * messageRevenue : 0

    // Link conversion rate
    const conversionRate =
      linkClicks > 0 ? (100 / linkClicks) * newSubscriptions : 0

    // const baseUrl = process.env.AXIOS_BASE_URL
    // Get from store.state.baseUrl
    // console.log('baseUrl', baseUrl)
    const img = `${baseUrl}/dashboard/api/v1/creator/${creator.id}/cropped`

    tableData.push({
      position,
      totalRevenue: formatCurrency(totalRevenue),
      growthOfTotalRevenue: '-',
      newSubs: newSubscriptions.toString(),
      newSubsRevenue: formatCurrency(newSubscriptionsRevenue),
      recSubsRevenue: formatCurrency(recurringSubscriptionsRevenue),
      messageRevenue: formatCurrency(messageRevenue),
      tipsRevenue: formatCurrency(tipsRevenue),
      postsRevenue: formatCurrency(postsRevenue),
      textingRevenueStake: textingRevenueStake.toFixed(2) + '%',
      linkClicks: linkClicks.toString(),
      conversionRate: conversionRate.toFixed(2) + '%',
      imgSrc: creator.id !== 0 ? img : undefined,
      openChatCount: includeChatCount ? openChatCount.toLocaleString() : 'N/A',
      sellingChatCount: includeChatCount
        ? sellingChatCount.toLocaleString()
        : 'N/A',
    })
  }

  return reverseTableData(tableData)
}

declare global {}
