import { useAppDispatch, useAppSelector } from '@/app/hooks'
import { getCalendars } from '@/features/Calendars/CalendarApi'
import { Calendar } from '@/features/Calendars/CalendarTypes'
import { addSharedCalendarAsync } from '@/features/Calendars/services'
import { CalendarData } from '@/features/Calendars/types/CalendarData'
import { renameDefault } from '@/utils/renameDefault'
import {
  Avatar,
  Box,
  Button,
  IconButton,
  TextField,
  Typography,
  useTheme
} from '@linagora/twake-mui'
import CloseIcon from '@mui/icons-material/Close'
import { useState } from 'react'
import { useI18n } from 'twake-i18n'
import { PeopleSearch } from '../Attendees/PeopleSearch'
import { User } from '../Attendees/types'
import { ResponsiveDialog } from '../Dialog'
import { stringAvatar } from '../Event/utils/eventUtils'
import { ColorPicker } from './CalendarColorPicker'
import { getAccessiblePair } from '@/utils/getAccessiblePair'
import { defaultColors } from '@/utils/defaultColors'

interface CalendarWithOwner {
  cal: CalendarData
  owner: User
}

function CalendarItem({
  cal,
  onRemove,
  onColorChange
}: {
  cal: CalendarWithOwner
  onRemove: () => void
  onColorChange: (color: Record<string, string>) => void
}) {
  const theme = useTheme()
  const { t } = useI18n()
  return (
    <Box
      key={cal.owner.email + cal.cal['dav:name']}
      display="flex"
      flexDirection="column"
      alignItems="flex-start"
      style={{
        borderRadius: 8,
        border: '1px solid #e5e7eb',
        padding: 8,
        marginBottom: 8
      }}
    >
      <Box display="flex" alignItems="center" gap={2} mb={1}>
        <Avatar
          {...stringAvatar(cal.owner.displayName || cal.owner.email)}
          style={{
            border: `2px solid ${cal.cal['apple:color'] || defaultColors[0].light}`,
            boxShadow: cal.cal['apple:color']
              ? `0 0 0 2px ${cal.cal['apple:color']}`
              : `0 0 0 2px ${defaultColors[0].light}`
          }}
        />
        <Box>
          <Typography variant="body1">
            {renameDefault(
              cal.cal['dav:name'],
              cal.owner.displayName,
              t,
              false
            )}
          </Typography>
          <Typography variant="body2" color="textSecondary">
            {cal.owner.email}
          </Typography>
        </Box>
      </Box>

      <Box display="flex" alignItems="center" gap={1}>
        <ColorPicker
          selectedColor={{
            light: cal.cal['apple:color'] ?? defaultColors[0].light,
            dark: cal.cal['apple:color']
              ? getAccessiblePair(cal.cal['apple:color'], theme)
              : defaultColors[0].dark
          }}
          onChange={onColorChange}
        />
        <IconButton size="small" onClick={onRemove}>
          <CloseIcon fontSize="small" />
        </IconButton>
      </Box>
    </Box>
  )
}

function SelectedCalendarsList({
  calendars,
  selectedCal,
  onRemove,
  onColorChange
}: {
  calendars: Record<string, Calendar>
  selectedCal: CalendarWithOwner[]
  onRemove: (cal: CalendarWithOwner) => void
  onColorChange: (cal: CalendarWithOwner, color: Record<string, string>) => void
}) {
  const { t } = useI18n()
  if (selectedCal.length === 0) return null

  const groupedByOwner = selectedCal.reduce<
    Record<
      string,
      {
        owner: User
        visibleCals: CalendarWithOwner[]
        alreadyExisting: boolean
      }
    >
  >((acc, cal) => {
    const exists = Object.values(calendars).some(
      (existing: Calendar) =>
        existing.id ===
        cal.cal?._links?.self?.href
          ?.replace('/calendars/', '')
          .replace('.json', '')
    )

    if (!acc[cal.owner.email]) {
      acc[cal.owner.email] = {
        owner: cal.owner,
        visibleCals: [],
        alreadyExisting: false
      }
    }

    if (exists) {
      acc[cal.owner.email].alreadyExisting = true
    } else {
      acc[cal.owner.email].visibleCals.push(cal)
    }

    return acc
  }, {})

  return (
    <Box mt={2}>
      <Typography variant="subtitle1" gutterBottom>
        {t('common.name')}
      </Typography>

      {Object.values(groupedByOwner).map(
        ({ owner, visibleCals, alreadyExisting }) => (
          <Box key={owner.email} mb={2}>
            {visibleCals.length > 0 ? (
              visibleCals.map(cal =>
                cal.cal ? (
                  <CalendarItem
                    key={cal.owner.email + cal.cal['dav:name']}
                    cal={cal}
                    onRemove={() => onRemove(cal)}
                    onColorChange={color => onColorChange(cal, color)}
                  />
                ) : (
                  <Typography
                    key={t('calendar.noPublicCalendarsFor', {
                      name: owner.displayName
                    })}
                    color="textSecondary"
                  >
                    {t('calendar.noPublicCalendarsFor', {
                      name: owner.displayName
                    })}
                  </Typography>
                )
              )
            ) : alreadyExisting ? (
              <Typography
                key={t('calendar.noMoreCalendarsFor', {
                  name: owner.displayName
                })}
                color="textSecondary"
              >
                {t('calendar.noMoreCalendarsFor', { name: owner.displayName })}
              </Typography>
            ) : null}
          </Box>
        )
      )}
    </Box>
  )
}

export default function CalendarSearch({
  open,
  onClose
}: {
  open: boolean
  onClose: (
    result?: string[] | Record<string, never>,
    reason?: 'backdropClick' | 'escapeKeyDown'
  ) => void
}) {
  const dispatch = useAppDispatch()
  const theme = useTheme()

  const openpaasId =
    useAppSelector(state => state.user.userData?.openpaasId) ?? ''
  const calendars = useAppSelector(state => state.calendars.list)

  const [selectedCal, setSelectedCalendars] = useState<CalendarWithOwner[]>([])
  const [selectedUsers, setSelectedUsers] = useState<User[]>([])

  const handleSave = async () => {
    if (selectedCal.length > 0) {
      const idList = await Promise.all(
        selectedCal.map(async cal => {
          const calId = crypto.randomUUID()
          const exists = Object.values(calendars).some(
            (existing: Calendar) =>
              existing.id ===
              cal.cal?._links?.self?.href
                ?.replace('/calendars/', '')
                .replace('.json', '')
          )
          if (!exists && cal.cal) {
            await dispatch(
              addSharedCalendarAsync({
                userId: openpaasId,
                calId,
                cal: {
                  ...cal,
                  color: cal.cal['apple:color']
                    ? {
                        light: cal.cal['apple:color'],
                        dark: getAccessiblePair(cal.cal['apple:color'], theme)
                      }
                    : defaultColors[0]
                }
              })
            )
            return cal.cal._links.self?.href
              ?.replace('/calendars/', '')
              .replace('.json', '')
          }
          return null
        })
      )

      onClose(idList.filter(Boolean) as string[])
      setSelectedCalendars([])
      setSelectedUsers([])
    }
  }
  const { t } = useI18n()

  return (
    <ResponsiveDialog
      open={open}
      contentSx={{ paddingTop: '8px !important' }}
      onClose={() => {
        onClose({}, 'backdropClick')
        setSelectedCalendars([])
        setSelectedUsers([])
      }}
      title={t('calendar.browseOtherCalendars')}
      actions={
        <>
          <Button
            variant="outlined"
            onClick={() => onClose({}, 'backdropClick')}
          >
            {t('common.cancel')}
          </Button>
          <Button variant="contained" onClick={handleSave}>
            {t('actions.add')}
          </Button>
        </>
      }
    >
      <PeopleSearch
        objectTypes={['user']}
        selectedUsers={selectedUsers}
        inputSlot={params => <TextField {...params} size="small" />}
        onChange={async (_event: React.SyntheticEvent, value: User[]) => {
          setSelectedUsers(value)

          const cals = await Promise.all(
            value.map(async (user: User) => {
              if (user?.openpaasId) {
                const cals = await getCalendars(
                  user.openpaasId,
                  'sharedPublic=true&'
                )
                return cals._embedded?.['dav:calendar']
                  ? cals._embedded['dav:calendar'].map(cal => ({
                      cal,
                      owner: user
                    }))
                  : { cal: undefined, owner: user }
              }
              return null
            })
          )
          setSelectedCalendars(
            cals.flat().filter(Boolean) as CalendarWithOwner[]
          )
        }}
      />

      <SelectedCalendarsList
        calendars={calendars}
        selectedCal={selectedCal}
        onRemove={cal => {
          if (!cal.cal?._links?.self?.href) return
          setSelectedCalendars(prev =>
            prev.filter(
              c => c.cal?._links?.self?.href !== cal.cal._links.self?.href
            )
          )
          if (
            !selectedCal.find(
              c =>
                cal.owner.email === c.owner.email &&
                c.cal?._links?.self?.href !== cal.cal._links.self?.href
            )
          ) {
            setSelectedUsers(prev =>
              prev.filter(u => u.email !== cal.owner.email)
            )
          }
        }}
        onColorChange={(cal, color) =>
          setSelectedCalendars(prev =>
            prev.map(prevcal =>
              prevcal.owner.email === cal.owner.email &&
              prevcal.cal._links.self?.href === cal.cal._links.self?.href
                ? {
                    ...prevcal,
                    cal: {
                      ...prevcal.cal,
                      'apple:color': color.light
                    }
                  }
                : prevcal
            )
          )
        }
      />
    </ResponsiveDialog>
  )
}
