import { css } from '@emotion/css'
import type { EmailDetails } from '@inject/graphql/fragments/EmailDetails.generated'
import type { EmailThread } from '@inject/graphql/fragments/EmailThread.generated'
import type { Exercise } from '@inject/graphql/fragments/Exercise.generated'
import type { ExerciseConfig } from '@inject/graphql/fragments/ExerciseConfig.generated'
import type { Team } from '@inject/graphql/fragments/Team.generated'
import type { Tool } from '@inject/graphql/fragments/Tool.generated'
import type { LogType } from '@inject/graphql/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'

export const formatTimestamp = (timestamp: string | null) => {
  const date = new Date(timestamp || 0)
  return `${date.toISOString().substring(0, 10)} ${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: LogType[] = [
  '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 const HEALTH_CHECK_INTERVAL = 3000

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

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: '',
  defaultResponse: '',
  tooltipDescription: 'An email sent by a team through the INJECT platform',
  hint: '',
  definition: {
    id: null,
    name: null,
  },
}
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 = 'rgba(143, 153, 168, 0.15)'
export const ACTIVE_COLOR = 'rgba(143, 153, 168, 0.3)'

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: null,
  teams: [],
  emailParticipants: [],
  timeDelta: 0,
  definition: {
    id: null,
    name: null,
  },
  name: '',
  userSet: [],
}
export const DUMMY_EXERCISE_CONFIG: ExerciseConfig = {
  exerciseDuration: 0,
  emailBetweenTeams: false,
  enableRoles: null,
  customEmailSuffix: null,
  showExerciseTime: null,
}

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 ellipsized = css`
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
`

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

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