import { Colors } from '@blueprintjs/colors'
import { css } from '@emotion/css'
import type {
  ActionLog,
  EmailDetails,
  EmailThread,
  Exercise,
  Team,
  Tool,
} from '@inject/graphql/fragment-types'
import { scaleOrdinal } from 'd3-scale'
import { schemeDark2 } from 'd3-scale-chromatic'
import {
  timeDay,
  timeHour,
  timeMinute,
  timeMonth,
  timeSecond,
  timeWeek,
  timeYear,
} from 'd3-time'
import { timeFormat } from 'd3-time-format'
import type { SVGProps } from 'react'

// TODO: move components used outside of analyst to shared/components

export const formatTimestamp = (timestamp: string | null) => {
  const date = new Date(timestamp || 0)
  return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`
}

export const formatTimestampRelative = (
  timestamp: string | null,
  start: string | null
) =>
  new Date(
    new Date(timestamp || 0).getTime() - (start ? new Date(start).getTime() : 0)
  )
    .toISOString()
    .substring(11, 19)

export const multiFormat = (date: Date, relative = false) => {
  let formatter

  if (timeSecond(date) < date) formatter = timeFormat('.%L')
  else if (timeMinute(date) < date) formatter = timeFormat(':%S')
  else if (timeHour(date) < date) {
    formatter = relative
      ? // when using time relative to the start of the exercise, return hours in GMT
        (d: Date) => d.toISOString().substring(11, 16)
      : timeFormat('%H:%M')
  } else if (timeDay(date) < date) {
    formatter = relative
      ? // when using time relative to the start of the exercise, return hours in GMT
        (d: Date) => d.toISOString().substring(11, 16)
      : timeFormat('%H:%M')
  } else if (timeMonth(date) < date) {
    formatter =
      timeWeek(date) < date ? timeFormat('%a %d') : timeFormat('%b %d')
  } else if (timeYear(date) < date) formatter = timeFormat('%B')
  else formatter = timeFormat('%Y')

  return formatter(date)
}

export const ACTION_TYPES: ActionLog['type'][] = [
  'INJECT',
  'CUSTOM_INJECT',
  'TOOL',
  'EMAIL',
  'FORM',
]
export const actionTypeColor = scaleOrdinal(schemeDark2).domain(ACTION_TYPES)

export const NOTHING_SELECTED_OPACITY = 0.7
export const SELECTED_OPACITY = 1
export const NOT_SELECTED_OPACITY = 0.3

export const LABEL_SELECTED_OPACITY = 1
export const LABEL_NOT_SELECTED_OPACITY = 0.4

export const MIN_TO_MS = 60000

export const DATA_ELEMENT_SIZE = 14
export const LEGEND_ELEMENT_SIZE = DATA_ELEMENT_SIZE * (7 / 10)

export const legendIconProps: SVGProps<SVGSVGElement> = {
  width: LEGEND_ELEMENT_SIZE,
  height: LEGEND_ELEMENT_SIZE,
  x: -LEGEND_ELEMENT_SIZE / 2,
  y: -LEGEND_ELEMENT_SIZE / 2,
}

export const compareDates = (a: Date, b: Date): number => {
  if (a < b) return -1
  if (a > b) return +1
  return 0 // dates are equal
}

export enum EmailSelection {
  SENT = 'sent',
  RECEIVED = 'received',
  DRAFTS = 'drafts',
  ARCHIVED = 'archived',
}

export enum VIEW {
  TABLE = 'th',
  PLOT = 'grouped-bar-chart',
}

export const UNDEFINED_TEAM_ID = 0

export const emailsSentByTeam = (
  emailThreads: EmailThread[],
  team: Team | undefined
) =>
  emailThreads
    .map(
      emailThread =>
        emailThread.emails.filter(
          email =>
            (team && email.sender.team?.id === team.id) ||
            (!team && email.sender.team)
        ).length
    )
    .reduce((a, b) => a + b, 0)

export const getRecipients = (emailDetails: EmailDetails) =>
  emailDetails.thread.participants.filter(
    participant => participant.id !== emailDetails.sender.id
  )

export const injectEmailTool: Tool = {
  id: '0',
  name: 'INJECT email',
  roles: '',
  requiresInput: false,
  defaultResponse: {
    id: '0',
    raw: '',
    rendered: '',
    fileInfo: null,
  },
  tooltipDescription: 'An email sent by a team through the INJECT platform',
  hint: '',
  definition: {
    id: '0',
    name: '',
  },
  category: '',
}
export const getInjectEmailArgument = (emailDetails: EmailDetails) =>
  `to: ${getRecipients(emailDetails)
    .map(recipient => recipient.address)
    .join(', ')}`
export const getInjectEmailResponse = () =>
  'For more information about INJECT emails, go to the Emails page'

export const HIGHLIGHTED_COLOR = `${Colors.GRAY3}26`
export const ACTIVE_COLOR = `${Colors.GRAY3}4d`

export const getTeamById = (teams: Team[], id: string) =>
  teams.filter(team => team.id === id).at(0)

export const DUMMY_EXERCISE: Exercise = {
  id: '',
  running: false,
  finished: false,
  exerciseStart: new Date(0).toUTCString(),
  teams: [],
  timeDelta: 0,
  definition: {
    id: '0',
    name: '',
  },
  name: '',
  instructors: [],
  createdBy: null,
  timestampCreated: '',
  config: {
    id: '0',
    customEmailSuffix: '',
    exerciseDuration: 0,
    updateIntervalS: 0,
    enabledFeatures: [],
  },
}

export const getIntent = (progress: number) => {
  if (progress < 0.33) {
    return 'danger'
  }
  if (progress < 0.66) {
    return 'warning'
  }
  return 'success'
}

export const DEFAULT_PLOT_MARGIN = 20

export interface PlotContextProps<X, Y> {
  width: number
  height: number
  xScale: X
  yScale: Y
}

export const highlighted = css`
  background-color: ${HIGHLIGHTED_COLOR};
`

export const highlightedOnHover = css`
  &:hover {
    background-color: ${HIGHLIGHTED_COLOR};
  }
`
export const highlightedOnActive = css`
  &:active {
    background-color: ${ACTIVE_COLOR};
  }
`

export const plotDataElement = css`
  stroke: transparent;
  stroke-width: 0.25rem;

  &:hover {
    filter: drop-shadow(0 0 0.125rem #202020);
    opacity: 1;
  }
`
