import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { sendRpcRequest } from "../../services/apiClient";

export interface IApp {
  pkgName: string;
  appName: string;
  appVer: string;
  appVerInt: number;
  appIcon: string;
}

interface AppsState {
  allApps: IApp[];
  blackList: IApp[];
  whiteList: IApp[];
  isLoadingAllApps: boolean;
  isLoadingBlackList: boolean;
  isLoadingWhiteList: boolean;
}

const initialState: AppsState = {
  allApps: [],
  blackList: [],
  whiteList: [],
  isLoadingAllApps: false,
  isLoadingBlackList: false,
  isLoadingWhiteList: false,
};

export const fetchAppList = createAsyncThunk(
  "apps/fetchAllApps",
  async (deviceId: string, { rejectWithValue }) => {
    try {
      const response = await sendRpcRequest<{ list: IApp[] }>("apps.applist", {
        deviceId,
        wIcons: true,
      });

      return response.list;
    } catch (error) {
      if (typeof error === "object" && error !== null && "message" in error) {
        return rejectWithValue(error.message);
      }

      return rejectWithValue("Unknown error occurred");
    }
  }
);

export const fetchBlackList = createAsyncThunk(
  "apps/fetchBlackList",
  async (deviceId: string, { rejectWithValue, getState }) => {
    try {
      const response = await sendRpcRequest<{ list: string[] }>(
        "apps.blacklist",
        {
          deviceId,
        }
      );
      const state = getState() as { apps: AppsState };
      const allApps = state.apps.allApps;

      const filtered = allApps.filter((app) =>
        response.list.includes(app.pkgName)
      );

      return filtered;
    } catch (error) {
      if (typeof error === "object" && error !== null && "message" in error) {
        return rejectWithValue(error.message);
      }

      return rejectWithValue("Unknown error occurred");
    }
  }
);

export const fetchWhiteList = createAsyncThunk(
  "apps/fetchWhiteList",
  async (deviceId: string, { rejectWithValue, getState, dispatch }) => {
    const state = getState() as { apps: AppsState };

    if (state.apps.allApps.length === 0) {
      const result = await dispatch(fetchAppList(deviceId));
      if (fetchAppList.rejected.match(result)) {
        return rejectWithValue("Failed to fetch all apps before whitelist.");
      }
    }

    try {
      const response = await sendRpcRequest<{ list: string[] }>(
        "apps.whitelist",
        { deviceId }
      );

      const updatedState = getState() as { apps: AppsState };
      const allApps = updatedState.apps.allApps;

      const filtered = allApps.filter((app) =>
        response.list.includes(app.pkgName)
      );

      return filtered;
    } catch (error) {
      if (typeof error === "object" && error !== null && "message" in error) {
        return rejectWithValue(error.message);
      }

      return rejectWithValue("Unknown error occurred");
    }
  }
);

const appsSlice = createSlice({
  name: "apps",
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchAppList.pending, (state) => {
        state.isLoadingAllApps = true;
      })
      .addCase(fetchAppList.fulfilled, (state, action) => {
        state.isLoadingAllApps = false;
        state.allApps = action.payload;
      })
      .addCase(fetchAppList.rejected, (state) => {
        state.isLoadingAllApps = false;
      })

      .addCase(fetchBlackList.pending, (state) => {
        state.isLoadingBlackList = true;
      })
      .addCase(fetchBlackList.fulfilled, (state, action) => {
        state.isLoadingBlackList = false;
        state.blackList = action.payload;
      })
      .addCase(fetchBlackList.rejected, (state) => {
        state.isLoadingBlackList = false;
      })

      .addCase(fetchWhiteList.pending, (state) => {
        state.isLoadingWhiteList = true;
      })
      .addCase(fetchWhiteList.fulfilled, (state, action) => {
        state.isLoadingWhiteList = false;
        state.whiteList = action.payload;
      })
      .addCase(fetchWhiteList.rejected, (state) => {
        state.isLoadingWhiteList = false;
      });
  },
});

export default appsSlice.reducer;
