import { z } from 'zod'
import type { NuxtAxiosInstance } from '@nuxtjs/axios'
import {dateToString} from "~/types/index";

export const ChatterSchema = z.object({
  minutesActive: z.number(),
  minutesInactive: z.number(),
  netSoldRevenue: z.number().nullish(),
  netTipsRevenue: z.number().nullish(),
  totalNetRevenue: z.number().nullish(),
  sendMediaMessages: z.number(),
  boughtMediaMessages: z.number(),
  sendMessages: z.number(),
  keystrokes: z.number(),
  averageResponseTime: z.number(),
})

export const ListChattersResponse = z.record(z.string(), ChatterSchema)

export type Chatter = z.infer<typeof ChatterSchema> & {
  name: string
}

export async function listChatters(
  axios: NuxtAxiosInstance,
  creatorId: number,
  from: Date,
  to: Date,
): Promise<Chatter[]> {
  const response = await axios.$get(
    `/dashboard/api/v1/creator/${creatorId}/tracking${createDatesQuery(
      from,
      to,
    )}`,
  )
  const chatters = ListChattersResponse.parse(response)
  return Object.entries(chatters).map(([name, chatter]) => ({
    ...chatter,
    name,
  }))
}

export const createDatesQuery = (from: Date, to: Date) => {
  let fromString = dateToString(from);
  let toString = dateToString(to);

  let query = `?start=${fromString}&end=${toString}`;

  if(fromString === toString) {
    query += "&hourly=true";
  }

  return query;
}

export const ChatterTimeSeriesEntrySchema = z.object({
  minutesActive: z.number(),
  minutesInactive: z.number(),
  netSoldRevenue: z.number().nullish(),
  netTipsRevenue: z.number().nullish(),
  totalNetRevenue: z.number().nullish(),
  sendMediaMessages: z.number(),
  boughtMediaMessages: z.number(),
  sendMessages: z.number(),
  keystrokes: z.number(),
})

export const ChatterTimeSeriesResponse = z.record(
  z.string(),
  ChatterTimeSeriesEntrySchema,
)

export type ChatterTimeSeriesEntry = z.infer<
  typeof ChatterTimeSeriesEntrySchema
> & {
  date: Date
}

export async function listChatterTimeSeries(
  axios: NuxtAxiosInstance,
  creatorId: number,
  browserName: string,
  from: Date,
  to: Date,
): Promise<ChatterTimeSeriesEntry[]> {
  const response = await axios.$get(
    `/dashboard/api/v1/creator/${creatorId}/tracking/${browserName}${createDatesQuery(
      from,
      to,
    )}`,
  )
  const chatters = ChatterTimeSeriesResponse.parse(response)
  const entries = Object.entries(chatters).map(([date, chatter]) => ({
    ...chatter,
    date: new Date(date),
  }))
  return entries.length >= 30 ? splitIntoMonths(entries) : entries
}

function splitIntoMonths(entries: ChatterTimeSeriesEntry[]) {
  const table = new Map<string, ChatterTimeSeriesEntry>()
  for (const entry of entries) {
    const key = `${entry.date.getFullYear()}-${entry.date.getMonth()}`
    if (!table.has(key)) {
      const beginningOfMonth = new Date(entry.date)
      beginningOfMonth.setDate(1)
      table.set(key, { ...entry, date: beginningOfMonth })
      continue;
    }

    add(table.get(key)!, [entry])
  }
  return [...table.values()].sort((a, b) => a.date.getTime() - b.date.getTime())
}

function add(
  result: ChatterTimeSeriesEntry,
  entries: ChatterTimeSeriesEntry[],
) {
  for (const entry of entries) {
    result.minutesActive += entry.minutesActive
    result.minutesInactive += entry.minutesInactive
    if (!result.netSoldRevenue) {
      result.netSoldRevenue = 0
    }
    result.netSoldRevenue += entry.netSoldRevenue ?? 0
    if (!result.netTipsRevenue) {
      result.netTipsRevenue = 0
    }
    result.netTipsRevenue += entry.netTipsRevenue ?? 0
    if (!result.totalNetRevenue) {
      result.totalNetRevenue = 0
    }
    result.totalNetRevenue += entry.totalNetRevenue ?? 0
    result.sendMediaMessages += entry.sendMediaMessages
    result.boughtMediaMessages += entry.boughtMediaMessages
    result.sendMessages += entry.sendMessages
    result.keystrokes += entry.keystrokes
  }
  return result
}
