import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { sendRpcRequest } from "../../services/apiClient";
import type {
  IAudioList,
  IDevice,
  IDeviceData,
} from "../../types/device.types";

interface IDeviceState {
  devices: IDevice[];
  deviceData: IDeviceData | null;
  selectedDevice: IDevice | null;
  audioList: IAudioList[];
  isAudioListLoading: boolean;
  loadingDevices: boolean;
  errorDevices: string;
  isEditingDevice?: boolean;
  isDeletingDevice: boolean;
}

const initialState: IDeviceState = {
  devices: [],
  deviceData: null,
  selectedDevice: null,
  audioList: [],
  isAudioListLoading: false,
  loadingDevices: false,
  errorDevices: "",
  isEditingDevice: false,
  isDeletingDevice: false,
};

export const fetchDevices = createAsyncThunk(
  "device/fetchDevices",
  async (_, { rejectWithValue }) => {
    try {
      const response = await sendRpcRequest<{ list: IDevice[] }>(
        "devices.getlist"
      );

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

      return rejectWithValue("Unknown error occurred");
    }
  },
  {
    condition: (_, { getState }) => {
      const state = getState() as { device: IDeviceState };

      return state.device.devices.length === 0;
    },
  }
);

export const fetchDeviceData = createAsyncThunk(
  "device/fetchDeviceData",
  async (deviceId: string, { rejectWithValue }) => {
    try {
      const response = await sendRpcRequest<IDeviceData>(
        "devices.getdevicedata",
        {
          deviceId,
        }
      );

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

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

export const fetchAudioFiles = createAsyncThunk(
  "device/fetchAudioFiles",
  async (
    {
      deviceId,
      dateFrom,
      dateTo,
      appId,
    }: {
      deviceId: string;
      dateFrom: Date;
      dateTo: Date;
      appId: number;
    },
    { rejectWithValue }
  ) => {
    try {
      const response = await sendRpcRequest<{ list: IAudioList[] }>(
        "data.getMedia",
        {
          deviceId,
          type: appId,
          dateFrom,
          dateTo,
          recStart: 0,
          recLimit: 50,
        }
      );

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

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

export const editDevice = createAsyncThunk(
  "device/editDevice",
  async (
    { deviceId, name }: { deviceId: string; name: string },
    { rejectWithValue }
  ) => {
    try {
      const response = await sendRpcRequest("devices.setDeviceName", {
        deviceId,
        name,
      });

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

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

// force refresh (no condition)
export const refreshDevices = createAsyncThunk(
  "device/refreshDevices",
  async (_, { rejectWithValue }) => {
    try {
      const response = await sendRpcRequest<{ list: IDevice[] }>(
        "devices.getlist"
      );
      return response.list;
    } catch (error: unknown) {
      if (typeof error === "object" && error !== null && "message" in error) {
        return rejectWithValue(error.message);
      }

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

export const deleteDevice = createAsyncThunk(
  "device/deleteDevice",
  async (deviceId: string, { rejectWithValue }) => {
    try {
      const response = await sendRpcRequest<{ success: boolean }>(
        "devices.deleteDevice",
        { deviceId }
      );

      if (response.success) {
        fetchDevices();
      }

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

const deviceSlice = createSlice({
  name: "device",
  initialState,
  reducers: {
    setSelectedDevice: (state, action) => {
      const selected = state.devices.find((d) => d.id === action.payload);
      state.selectedDevice = selected ?? null;
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchDevices.pending, (state) => {
        state.loadingDevices = true;
      })
      .addCase(fetchDevices.fulfilled, (state, action) => {
        state.loadingDevices = false;
        state.devices = action.payload;
        state.selectedDevice = action.payload[0] ?? null;
      })
      .addCase(fetchDevices.rejected, (state, action) => {
        state.loadingDevices = false;
        state.errorDevices = action.payload as string;
      })

      .addCase(fetchDeviceData.fulfilled, (state, action) => {
        state.deviceData = action.payload;
      })

      .addCase(editDevice.pending, (state) => {
        state.isEditingDevice = true;
      })
      .addCase(editDevice.fulfilled, (state) => {
        state.isEditingDevice = false;
      })
      .addCase(editDevice.rejected, (state, action) => {
        state.isEditingDevice = false;
        console.error("Error editing device:", action.payload);
      })

      .addCase(deleteDevice.pending, (state) => {
        state.isDeletingDevice = true;
      })
      .addCase(deleteDevice.fulfilled, (state) => {
        state.isDeletingDevice = false;
      })
      .addCase(deleteDevice.rejected, (state, action) => {
        state.isDeletingDevice = false;
        console.error("Error deleting device:", action.payload);
      })

      .addCase(fetchAudioFiles.pending, (state) => {
        state.isAudioListLoading = true;
      })
      .addCase(fetchAudioFiles.fulfilled, (state, action) => {
        state.isAudioListLoading = false;
        state.audioList = action.payload;
      })
      .addCase(fetchAudioFiles.rejected, (state, action) => {
        state.isAudioListLoading = false;
        console.error("Error fetching audio files:", action.payload);
      })

      .addCase(refreshDevices.fulfilled, (state, action) => {
        state.devices = action.payload;
        state.selectedDevice = action.payload[0] ?? null;
      });
  },
});

export const { setSelectedDevice } = deviceSlice.actions;
export default deviceSlice.reducer;
