import {createContext, useContext, useReducer} from 'react'
import {
  type AppBskyFeedDefs,
  type AppBskyGraphDefs,
  AppBskyGraphStarterpack,
} from '@atproto/api'
import {msg, plural} from '@lingui/core/macro'

import {STARTER_PACK_MAX_SIZE} from '#/lib/constants'
import * as Toast from '#/components/Toast'
import * as bsky from '#/types/bsky'

const steps = ['Details', 'Profiles', 'Feeds'] as const
type Step = (typeof steps)[number]

type Action =
  | {type: 'Next'}
  | {type: 'Back'}
  | {type: 'SetCanNext'; canNext: boolean}
  | {type: 'SetName'; name: string}
  | {type: 'SetDescription'; description: string}
  | {type: 'AddProfile'; profile: bsky.profile.AnyProfileView}
  | {type: 'RemoveProfile'; profileDid: string}
  | {type: 'AddFeed'; feed: AppBskyFeedDefs.GeneratorView}
  | {type: 'RemoveFeed'; feedUri: string}
  | {type: 'SetProcessing'; processing: boolean}
  | {type: 'SetError'; error: string}

interface State {
  canNext: boolean
  currentStep: Step
  name?: string
  description?: string
  profiles: bsky.profile.AnyProfileView[]
  feeds: AppBskyFeedDefs.GeneratorView[]
  processing: boolean
  error?: string
  transitionDirection: 'Backward' | 'Forward'
  targetDid?: string
}

type TStateContext = [State, (action: Action) => void]

const StateContext = createContext<TStateContext>([
  {} as State,
  (_: Action) => {},
])
StateContext.displayName = 'StarterPackWizardStateContext'
export const useWizardState = () => useContext(StateContext)

function reducer(state: State, action: Action): State {
  let updatedState = state

  // -- Navigation
  const currentIndex = steps.indexOf(state.currentStep)
  if (action.type === 'Next' && state.currentStep !== 'Feeds') {
    updatedState = {
      ...state,
      currentStep: steps[currentIndex + 1],
      transitionDirection: 'Forward',
    }
  } else if (action.type === 'Back' && state.currentStep !== 'Details') {
    updatedState = {
      ...state,
      currentStep: steps[currentIndex - 1],
      transitionDirection: 'Backward',
    }
  }

  switch (action.type) {
    case 'SetName':
      updatedState = {...state, name: action.name.slice(0, 50)}
      break
    case 'SetDescription':
      updatedState = {...state, description: action.description}
      break
    case 'AddProfile':
      if (state.profiles.length > STARTER_PACK_MAX_SIZE) {
        Toast.show(
          msg`You may only add up to ${plural(STARTER_PACK_MAX_SIZE, {
            other: `${STARTER_PACK_MAX_SIZE} profiles`,
          })}`.message ?? '',
          {
            type: 'info',
          },
        )
      } else {
        updatedState = {...state, profiles: [...state.profiles, action.profile]}
      }
      break
    case 'RemoveProfile':
      updatedState = {
        ...state,
        profiles: state.profiles.filter(
          profile => profile.did !== action.profileDid,
        ),
      }
      break
    case 'AddFeed':
      if (state.feeds.length >= 3) {
        Toast.show(msg`You may only add up to 3 feeds`.message ?? '', {
          type: 'info',
        })
      } else {
        updatedState = {...state, feeds: [...state.feeds, action.feed]}
      }
      break
    case 'RemoveFeed':
      updatedState = {
        ...state,
        feeds: state.feeds.filter(f => f.uri !== action.feedUri),
      }
      break
    case 'SetProcessing':
      updatedState = {...state, processing: action.processing}
      break
  }

  return updatedState
}

export function Provider({
  starterPack,
  listItems,
  targetProfile,
  children,
}: {
  starterPack?: AppBskyGraphDefs.StarterPackView
  listItems?: AppBskyGraphDefs.ListItemView[]
  targetProfile: bsky.profile.AnyProfileView
  children: React.ReactNode
}) {
  const createInitialState = (): State => {
    const targetDid = targetProfile?.did

    if (
      starterPack &&
      bsky.validate(starterPack.record, AppBskyGraphStarterpack.validateRecord)
    ) {
      return {
        canNext: true,
        currentStep: 'Details',
        name: starterPack.record.name,
        description: starterPack.record.description,
        profiles: listItems?.map(i => i.subject) ?? [],
        feeds: starterPack.feeds ?? [],
        processing: false,
        transitionDirection: 'Forward',
        targetDid,
      }
    }

    return {
      canNext: true,
      currentStep: 'Details',
      profiles: [targetProfile],
      feeds: [],
      processing: false,
      transitionDirection: 'Forward',
      targetDid,
    }
  }

  const [state, dispatch] = useReducer(reducer, null, createInitialState)

  return (
    <StateContext.Provider value={[state, dispatch]}>
      {children}
    </StateContext.Provider>
  )
}

export {
  type Action as WizardAction,
  type State as WizardState,
  type Step as WizardStep,
}
