import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";
import { NamedEntity } from "../model/NamedEntity";
import { serverUrl } from "../utils/request";

interface NamedEntityState {
    all: NamedEntity[];
    namedEntity: NamedEntity;
    history: NamedEntity[];
    status: string;
}

const initialState: NamedEntityState = {
    all: [],
    namedEntity: {} as NamedEntity,
    history: localStorage.getItem("namedEntityHistory") ? 
        JSON.parse(localStorage.getItem("namedEntityHistory") as string) : [],
    status: "idle",
};

const TIMEOUT = 5000;

export const fetchNamedEntities = createAsyncThunk<
    Array<NamedEntity>
>('namedEntities', async () => {
    const controller = new AbortController();
    const id = setTimeout(() => controller.abort(), TIMEOUT);

    const response = await fetch(serverUrl() + '/api/tags', { signal: controller.signal });
    clearTimeout(id);

    return (await response.json()).namedEntities as Array<NamedEntity>;
});

export const fetchNamedEntity = createAsyncThunk<
    NamedEntity,
    string | undefined
>('namedEntity', async (name: string | undefined) => {
    const controller = new AbortController();
    const idTimeout = setTimeout(() => controller.abort(), TIMEOUT);

    const response = await fetch(serverUrl() + `/api/tags/${name}`, { signal: controller.signal });
    clearTimeout(idTimeout);

    return (await response.json()).namedEntity as NamedEntity;
});

export const namedEntitySlice = createSlice({
    name: "namedEntity",
    initialState,
    reducers: {
        setAll(state: NamedEntityState, action: PayloadAction<Array<NamedEntity>>) {
            state.all = action.payload;
        },
        setNamedEntity(state: NamedEntityState, action: PayloadAction<NamedEntity>) {
            state.namedEntity = action.payload;
        },
        addToHistory(state: NamedEntityState, action: PayloadAction<NamedEntity>) {
            // add to history if exists put it at the top
            const history = state.history.filter((item) => item.name !== action.payload.name);
            state.history = [action.payload, ...history.slice(0, 9)];

            // save to local storage
            localStorage.setItem("namedEntityHistory", JSON.stringify(state.history));
        }
    },
    extraReducers: (builder) => {
        builder
            .addCase(fetchNamedEntities.pending, (state: NamedEntityState) => {
                state.status = 'loading';
            })
            .addCase(fetchNamedEntities.fulfilled, (state: NamedEntityState, action: PayloadAction<Array<NamedEntity>>) => {
                state.all = action.payload;
                state.status = 'idle';
            })
            .addCase(fetchNamedEntities.rejected, (state: NamedEntityState) => {
                state.status = 'failed';
            })
            .addCase(fetchNamedEntity.pending, (state: NamedEntityState) => {
                state.status = 'loading';
            })
            .addCase(fetchNamedEntity.fulfilled, (state: NamedEntityState, action: PayloadAction<NamedEntity>) => {
                state.namedEntity = action.payload;
                state.status = 'idle';
            })
            .addCase(fetchNamedEntity.rejected, (state: NamedEntityState) => {
                state.status = 'failed';
            });
    },
});

export const { addToHistory } = namedEntitySlice.actions;

export default namedEntitySlice.reducer;