import {
  CreateCustomer,
  CreatePassword,
  GetLoggedCustomer,
  SendCode,
  VerifyCode,
  VerifyCPF
} from '@agiliza/api/domain'
import { AuthenticationRepositoryImplFactory } from '@agiliza/api/useCases'
import { appPlatform } from '@agiliza/constants/platform'
import {
  createAsyncReducers,
  getTypesThunkActions,
  values,
  WithSuccess
} from '@agiliza/utils/method'
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'

const prefix = 'useCases/authentication'

export interface State {
  fetching: boolean
  sendingCode: boolean
}

export const initialState: State = {
  fetching: false,
  sendingCode: false,
}

export const actions = {
  getContext: createAsyncThunk(`${prefix}/getContext`, async (_, thunkApi) => {
    const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
    try {
      return await useCase.getContext()
    } catch (e) {
      return thunkApi.rejectWithValue(e)
    }
  }),
  verifyCPF: createAsyncThunk(`${prefix}/verifyCPF`, async (input: WithSuccess<VerifyCPF['Input']>, thunkApi) => {
    const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
    try {
      await useCase.verifyCPF(input)
      input.onSuccess && input.onSuccess()
    } catch (e) {
      return thunkApi.rejectWithValue(e)
    }
  }),
  createCustomer: createAsyncThunk(`${prefix}/createCustomer`, async (input: WithSuccess<CreateCustomer['Input']>, thunkApi) => {
    const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
    try {
      const customer = await useCase.createCustomer(input)
      input.onSuccess && input.onSuccess()
      return customer
    } catch (e) {
      return thunkApi.rejectWithValue(e)
    }
  }),
  sendCode: createAsyncThunk(`${prefix}/sendCode`, async (input: WithSuccess<SendCode['Input']>, thunkApi) => {
    const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
    try {
      await useCase.sendCode(input)
      input.onSuccess && input.onSuccess()
    } catch (e) {
      return thunkApi.rejectWithValue(e)
    }
  }),
  verifyCode: createAsyncThunk(`${prefix}/verifyCode`, async (input: WithSuccess<VerifyCode['Input']>, thunkApi) => {
    const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
    try {
      await useCase.verifyCode(input)
      input.onSuccess && input.onSuccess()
    } catch (e) {
      return thunkApi.rejectWithValue(e)
    }
  }),
  createPassword: createAsyncThunk(`${prefix}/createPassword`, async (input: WithSuccess<CreatePassword['Input']>, thunkApi) => {
    const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
    try {
      await useCase.createPassword(input)
      input.onSuccess && input.onSuccess()
    } catch (e) {
      return thunkApi.rejectWithValue(e)
    }
  }),
  getLoggedCustomer: createAsyncThunk(`${prefix}/getLoggedCustomer`, async (input: WithSuccess<GetLoggedCustomer['Input']>, thunkApi) => {
    const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
    try {
      const customer = await useCase.getLoggedCustomer()
      input.onSuccess && input.onSuccess()
      return customer
    } catch (e) {
      return thunkApi.rejectWithValue(e)
    }
  }),
} as const
export const types = getTypesThunkActions(actions)

const slice = createSlice({
  name: prefix,
  initialState,
  reducers: {},
  extraReducers: {
    ...values(types).reduce((reducers, type) => ({ ...reducers, ...createAsyncReducers(type) }), {}),
    ...createAsyncReducers(types.sendCode, 'sendingCode'),
  },
})

export default slice
