import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { RootState } from './rootReducer';
import axios from 'axios';
import moment, { Moment } from 'moment';

export type Status = 'none' | 'passive' | 'stopped' | 'scheduled';

function decodeStatus(agb): Status {
  const nexttasktime = moment(agb.agb_nextaufgabe);
  const year = nexttasktime.year();
  const isDeactivated = year === 2099;
  if (isDeactivated) {
    return 'stopped';
  }

  const isPassive = Number(agb.agb_intervall) === 6;
  if (isPassive) {
    return 'passive';
  }

  return 'scheduled';
}

function numberValidation(num: string) {
  let decimalUsed = false;
  let finalNum = '';
  const lang = document.documentElement.lang;
  for (let char of num) {
    // append number char
    const isNumber = /^[0-9]$/.test(char);
    if (isNumber) {
      finalNum += char;
      continue;
    }

    // handle decimal point
    const isDE = lang === 'de';
    const isFloat = isDE && char === ',' && decimalUsed === false;
    if (isFloat) {
      decimalUsed = true;
      finalNum += '.';
      continue;
    }
    const isNotDEFloat =
      isDE === false && char === '.' && decimalUsed === false;
    if (isNotDEFloat) {
      decimalUsed = true;
      finalNum += '.';
      continue;
    }
  }

  const numberToReturn = Number(finalNum);
  const isNotValidNumber = isNaN(numberToReturn);
  if (isNotValidNumber) return false;

  return numberToReturn;
}

interface InitArgs {
  ID: number;
  name: string;
}
export const fetchLatest = createAsyncThunk(
  'monitorpage/measurement-form',
  async (arg: InitArgs) => {
    const agbID = arg.ID;
    const r = await axios.get(`agb/${agbID}/latest`);
    const nextTaskTime = r.data.agb_nextaufgabe;

    const status = decodeStatus(r.data);
    const lastTaskTime = r.data.ergs?.[0]?.erg_datum ?? '';
    const lastValue = r.data.ergs?.[0]?.erg_value ?? '';

    return {
      nextTaskTime,
      status,
      lastTaskTime,
      lastValue,
      agbID,
      name: arg.name
    };
  }
);

interface RejectedType {
  isInvalidAgbID?: boolean;
  isInvalidNumber?: boolean;
}
export const submit = createAsyncThunk<
  void,
  void,
  { rejectValue: RejectedType }
>('monitorpage/measurement-form/submit', async (_arg, thunkAPI) => {
  const s = (thunkAPI.getState() as RootState).measurementForm;
  const valueToSubmit = numberValidation(s.value);
  const isInvalidNumber = valueToSubmit === false;
  if (isInvalidNumber) {
    return thunkAPI.rejectWithValue({ isInvalidNumber: true });
  }
  if (s.agbID === undefined) {
    return thunkAPI.rejectWithValue({ isInvalidAgbID: true });
  }

  axios.post('/erg/new/measurement', {
    agbId: s.agbID,
    time: s.datetime,
    value: valueToSubmit,
    difference: 0
  });
});

interface State {
  isOpen: boolean;
  status: Status;
  datetime: string;
  lastRecordTime: '';
  nextRecordTime: '';
  value: string;
  lastValue: string;
  isInvalidNumber: boolean;
  agbID?: number;
  name: string;
}
const initialState: State = {
  isOpen: false,
  status: 'none',
  datetime: '',
  lastRecordTime: '',
  nextRecordTime: '',
  value: '',
  lastValue: '',
  isInvalidNumber: false,
  name: ''
};

const slice = createSlice({
  name: 'monitorpage/measurement-form',
  initialState,
  reducers: {
    setStatus(state, { payload }: PayloadAction<Status>) {
      state.status = payload;
    },
    setDatetime(state, { payload }: PayloadAction<Moment>) {
      state.datetime = payload.toISOString();
    },
    setValue(state, { payload }: PayloadAction<string>) {
      if (payload === '') {
        state.value = '';
        return;
      }
      const isValid = /^[0-9.,]*$/.test(payload);
      if (isValid === false) return;
      state.value = payload;
    },
    openForm(state) {
      state.isOpen = true;
    },
    closeForm(state) {
      state.isOpen = false;
      state.status = 'none';
      state.datetime = '';
      state.lastRecordTime = '';
      state.nextRecordTime = '';
      state.value = '';
      state.lastValue = '';
    }
  },
  extraReducers: (builder) => {
    builder.addCase(fetchLatest.fulfilled, (state, { payload }) => {
      state.isOpen = true;
      state.agbID = payload.agbID;
      state.status = payload.status;
      state.nextRecordTime = payload.nextTaskTime;
      state.lastRecordTime = payload.lastTaskTime;
      state.lastValue = payload.lastValue;
      state.name = payload.name;
    });

    builder
      .addCase(submit.fulfilled, (state) => {
        state.isOpen = false;
        state.status = 'none';
        state.datetime = '';
        state.lastRecordTime = '';
        state.nextRecordTime = '';
        state.value = '';
        state.lastValue = '';
      })
      .addCase(submit.rejected, (state, { payload }) => {
        if (payload.isInvalidNumber) {
          state.isInvalidNumber = true;
        }
      });
  }
});

export const {
  setStatus,
  setDatetime,
  setValue,
  openForm,
  closeForm
} = slice.actions;
export default slice.reducer;
