// src/api.js (updated)
import useAuthStore from './store/auth';
import useChannelsStore from './store/channels';
import useUserAgentsStore from './store/userAgents';
import usePlaylistsStore from './store/playlists';
import useEPGsStore from './store/epgs';
import useStreamsStore from './store/streams';
import useStreamProfilesStore from './store/streamProfiles';
import useSettingsStore from './store/settings';
import { notifications } from '@mantine/notifications';
import useChannelsTableStore from './store/channelsTable';

// If needed, you can set a base host or keep it empty if relative requests
const host = import.meta.env.DEV
  ? `http://${window.location.hostname}:5656`
  : '';

const errorNotification = (message, error) => {
  let errorMessage = '';

  if (error.status) {
    try {
      // Try to format the error body if it's an object
      if (typeof error.body === 'object') {
        errorMessage = JSON.stringify(error.body, null, 2);
      } else {
        errorMessage = `${error.status} - ${error.body}`;
      }
    } catch (e) {
      errorMessage = `${error.status} - ${String(error.body)}`;
    }
  } else {
    errorMessage = error.message || 'Unknown error';
  }

  notifications.show({
    title: 'Error',
    message: `${message}: ${errorMessage}`,
    autoClose: 10000,
    color: 'red',
  });

  throw error;
};

const request = async (url, options = {}) => {
  if (
    options.body &&
    !(options.body instanceof FormData) &&
    typeof options.body === 'object'
  ) {
    options.body = JSON.stringify(options.body);
    options.headers = {
      ...options.headers,
      'Content-Type': 'application/json',
    };
  }

  if (options.auth !== false) {
    options.headers = {
      ...options.headers,
      Authorization: `Bearer ${await API.getAuthToken()}`,
    };
  }

  const response = await fetch(url, options);

  if (!response.ok) {
    const error = new Error(`HTTP error! Status: ${response.status}`);

    let errorBody = await response.text();

    try {
      errorBody = JSON.parse(errorBody);
    } catch (e) {
      // If parsing fails, leave errorBody as the raw text
    }

    error.status = response.status;
    error.response = response;
    error.body = errorBody;

    throw error;
  }

  try {
    const retval = await response.json();
    return retval;
  } catch (e) {
    return '';
  }
};

export default class API {
  static lastQueryParams = new URLSearchParams();

  /**
   * A static method so we can do:  await API.getAuthToken()
   */
  static async getAuthToken() {
    return await useAuthStore.getState().getToken();
  }

  static async fetchSuperUser() {
    try {
      const response = await request(
        `${host}/api/accounts/initialize-superuser/`,
        { auth: false }
      );

      return response;
    } catch (e) {
      errorNotification('Failed to fetch  superuser', e);
    }
  }

  static async createSuperUser({ username, email, password }) {
    try {
      const response = await request(
        `${host}/api/accounts/initialize-superuser/`,
        {
          auth: false,
          method: 'POST',
          body: {
            username,
            password,
            email,
          },
        }
      );

      return response;
    } catch (e) {
      errorNotification('Failed to create superuser', e);
    }
  }

  static async login(username, password) {
    try {
      const response = await request(`${host}/api/accounts/token/`, {
        auth: false,
        method: 'POST',
        body: { username, password },
      });

      return response;
    } catch (e) {
      errorNotification('Login failed', e);
    }
  }

  static async refreshToken(refresh) {
    return await request(`${host}/api/accounts/token/refresh/`, {
      auth: false,
      method: 'POST',
      body: { refresh },
    });
  }

  static async logout() {
    return await request(`${host}/api/accounts/auth/logout/`, {
      auth: false,
      method: 'POST',
    });
  }

  static async getChannels() {
    try {
      const response = await request(`${host}/api/channels/channels/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve channels', e);
    }
  }

  static async queryChannels(params) {
    try {
      API.lastQueryParams = params;

      const response = await request(
        `${host}/api/channels/channels/?${params.toString()}`
      );

      useChannelsTableStore.getState().queryChannels(response, params);

      return response;
    } catch (e) {
      errorNotification('Failed to fetch channels', e);
    }
  }

  static async requeryChannels() {
    try {
      const [response, ids] = await Promise.all([
        request(
          `${host}/api/channels/channels/?${API.lastQueryParams.toString()}`
        ),
        API.getAllChannelIds(API.lastQueryParams),
      ]);

      useChannelsTableStore
        .getState()
        .queryChannels(response, API.lastQueryParams);
      useChannelsTableStore.getState().setAllQueryIds(ids);

      return response;
    } catch (e) {
      errorNotification('Failed to fetch channels', e);
    }
  }

  static async getAllChannelIds(params) {
    try {
      const response = await request(
        `${host}/api/channels/channels/ids/?${params.toString()}`
      );

      return response;
    } catch (e) {
      errorNotification('Failed to fetch channel IDs', e);
    }
  }

  static async getChannelGroups() {
    try {
      const response = await request(`${host}/api/channels/groups/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve channel groups', e);
    }
  }

  static async addChannelGroup(values) {
    try {
      const response = await request(`${host}/api/channels/groups/`, {
        method: 'POST',
        body: values,
      });

      if (response.id) {
        useChannelsStore.getState().addChannelGroup(response);
      }

      return response;
    } catch (e) {
      errorNotification('Failed to create channel group', e);
    }
  }

  static async updateChannelGroup(values) {
    try {
      const { id, ...payload } = values;
      const response = await request(`${host}/api/channels/groups/${id}/`, {
        method: 'PUT',
        body: payload,
      });

      if (response.id) {
        useChannelsStore.getState().updateChannelGroup(response);
      }

      return response;
    } catch (e) {
      errorNotification('Failed to update channel group', e);
    }
  }

  static async addChannel(channel) {
    try {
      let body = null;
      if (channel.logo_file) {
        // Must send FormData for file upload
        body = new FormData();
        for (const prop in channel) {
          body.append(prop, channel[prop]);
        }
      } else {
        body = { ...channel };
        delete body.logo_file;
      }

      const response = await request(`${host}/api/channels/channels/`, {
        method: 'POST',
        body: body,
      });

      API.getLogos();

      if (response.id) {
        useChannelsStore.getState().addChannel(response);
      }

      return response;
    } catch (e) {
      errorNotification('Failed to create channel', e);
    }
  }

  static async deleteChannel(id) {
    try {
      await request(`${host}/api/channels/channels/${id}/`, {
        method: 'DELETE',
      });

      useChannelsStore.getState().removeChannels([id]);
    } catch (e) {
      errorNotification('Failed to delete channel', e);
    }
  }

  // @TODO: the bulk delete endpoint is currently broken
  static async deleteChannels(channel_ids) {
    try {
      await request(`${host}/api/channels/channels/bulk-delete/`, {
        method: 'DELETE',
        body: { channel_ids },
      });

      useChannelsStore.getState().removeChannels(channel_ids);
    } catch (e) {
      errorNotification('Failed to delete channels', e);
    }
  }

  static async updateChannel(values) {
    try {
      // Clean up values before sending to API
      const payload = { ...values };

      // Handle special values
      if (
        payload.stream_profile_id === '0' ||
        payload.stream_profile_id === 0
      ) {
        payload.stream_profile_id = null;
      }

      // Handle logo_id properly (0 means "no logo")
      if (payload.logo_id === '0' || payload.logo_id === 0) {
        payload.logo_id = null;
      }

      // Ensure tvg_id is included properly (not as empty string)
      if (payload.tvg_id === '') {
        payload.tvg_id = null;
      }

      // Ensure tvc_guide_stationid is included properly (not as empty string)
      if (payload.tvc_guide_stationid === '') {
        payload.tvc_guide_stationid = null;
      }

      // Handle channel_number properly
      if (payload.channel_number === '') {
        payload.channel_number = null;
      } else if (
        payload.channel_number !== null &&
        payload.channel_number !== undefined
      ) {
        const parsedNumber = parseInt(payload.channel_number, 10);
        payload.channel_number = isNaN(parsedNumber) ? null : parsedNumber;
      }

      const response = await request(
        `${host}/api/channels/channels/${payload.id}/`,
        {
          method: 'PATCH',
          body: payload,
        }
      );

      useChannelsStore.getState().updateChannel(response);
      return response;
    } catch (e) {
      errorNotification('Failed to update channel', e);
    }
  }

  static async updateChannels(ids, values) {
    const body = [];
    for (const id in ids) {
      body.push({
        id,
        ...values,
      });
    }

    try {
      const response = await request(
        `${host}/api/channels/channels/edit/bulk/`,
        {
          method: 'PATCH',
          body,
        }
      );

      useChannelsStore.getState().updateChannels(response);
      return response;
    } catch (e) {
      errorNotification('Failed to update channels', e);
    }
  }

  static async setChannelEPG(channelId, epgDataId) {
    try {
      const response = await request(
        `${host}/api/channels/channels/${channelId}/set-epg/`,
        {
          method: 'POST',
          body: { epg_data_id: epgDataId },
        }
      );

      // Update the channel in the store with the refreshed data
      if (response.channel) {
        useChannelsStore.getState().updateChannel(response.channel);
      }

      // Show notification about task status
      if (response.task_status) {
        notifications.show({
          title: 'EPG Status',
          message: response.task_status,
          color: 'blue',
        });
      }

      return response;
    } catch (e) {
      errorNotification('Failed to update channel EPG', e);
    }
  }

  static async assignChannelNumbers(channelIds, startingNum = 1) {
    try {
      const response = await request(`${host}/api/channels/channels/assign/`, {
        method: 'POST',
        body: { channel_ids: channelIds, starting_number: startingNum },
      });

      return response;
    } catch (e) {
      errorNotification('Failed to assign channel #s', e);
    }
  }

  static async createChannelFromStream(values) {
    try {
      const response = await request(
        `${host}/api/channels/channels/from-stream/`,
        {
          method: 'POST',
          body: values,
        }
      );

      if (response.id) {
        useChannelsStore.getState().addChannel(response);
      }

      return response;
    } catch (e) {
      errorNotification('Failed to create channel', e);
    }
  }

  static async createChannelsFromStreams(values) {
    try {
      const response = await request(
        `${host}/api/channels/channels/from-stream/bulk/`,
        {
          method: 'POST',
          body: values,
        }
      );

      if (response.created.length > 0) {
        useChannelsStore.getState().addChannels(response.created);
      }

      return response;
    } catch (e) {
      errorNotification('Failed to create channels', e);
    }
  }

  static async getStreams(ids = null) {
    try {
      const params = new URLSearchParams();
      if (ids) {
        params.append('ids', ids.join(','));
      }
      const response = await request(
        `${host}/api/channels/streams/?${params.toString()}`
      );

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve streams', e);
    }
  }

  static async getChannelStreams(id) {
    try {
      const response = await request(
        `${host}/api/channels/channels/${id}/streams/`
      );

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve channel streams', e);
    }
  }

  static async queryStreams(params) {
    try {
      const response = await request(
        `${host}/api/channels/streams/?${params.toString()}`
      );

      return response;
    } catch (e) {
      errorNotification('Failed to fetch streams', e);
    }
  }

  static async getAllStreamIds(params) {
    try {
      const response = await request(
        `${host}/api/channels/streams/ids/?${params.toString()}`
      );

      return response;
    } catch (e) {
      errorNotification('Failed to fetch stream IDs', e);
    }
  }

  static async getStreamGroups() {
    try {
      const response = await request(`${host}/api/channels/streams/groups/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve stream groups', e);
    }
  }

  static async addStream(values) {
    try {
      const response = await request(`${host}/api/channels/streams/`, {
        method: 'POST',
        body: values,
      });

      if (response.id) {
        useStreamsStore.getState().addStream(response);
      }

      return response;
    } catch (e) {
      errorNotification('Failed to add stream', e);
    }
  }

  static async updateStream(values) {
    try {
      const { id, ...payload } = values;
      const response = await request(`${host}/api/channels/streams/${id}/`, {
        method: 'PUT',
        body: payload,
      });

      if (response.id) {
        useStreamsStore.getState().updateStream(response);
      }

      return response;
    } catch (e) {
      errorNotification('Failed to update stream', e);
    }
  }

  static async deleteStream(id) {
    try {
      await request(`${host}/api/channels/streams/${id}/`, {
        method: 'DELETE',
      });

      useStreamsStore.getState().removeStreams([id]);
    } catch (e) {
      errorNotification('Failed to delete stream', e);
    }
  }

  static async deleteStreams(ids) {
    try {
      await request(`${host}/api/channels/streams/bulk-delete/`, {
        method: 'DELETE',
        body: { stream_ids: ids },
      });

      useStreamsStore.getState().removeStreams(ids);
    } catch (e) {
      errorNotification('Failed to delete streams', e);
    }
  }

  static async getUserAgents() {
    try {
      const response = await request(`${host}/api/core/useragents/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve user-agents', e);
    }
  }

  static async addUserAgent(values) {
    try {
      const response = await request(`${host}/api/core/useragents/`, {
        method: 'POST',
        body: values,
      });

      useUserAgentsStore.getState().addUserAgent(response);

      return response;
    } catch (e) {
      errorNotification('Failed to create user-agent', e);
    }
  }

  static async updateUserAgent(values) {
    try {
      const { id, ...payload } = values;
      const response = await request(`${host}/api/core/useragents/${id}/`, {
        method: 'PUT',
        body: payload,
      });

      useUserAgentsStore.getState().updateUserAgent(response);

      return response;
    } catch (e) {
      errorNotification('Failed to update user-agent', e);
    }
  }

  static async deleteUserAgent(id) {
    try {
      await request(`${host}/api/core/useragents/${id}/`, {
        method: 'DELETE',
      });

      useUserAgentsStore.getState().removeUserAgents([id]);
    } catch (e) {
      errorNotification('Failed to delete user-agent', e);
    }
  }

  static async getPlaylist(id) {
    try {
      const response = await request(`${host}/api/m3u/accounts/${id}/`);

      return response;
    } catch (e) {
      errorNotification(`Failed to retrieve M3U account ${id}`, e);
    }
  }

  static async getPlaylists() {
    try {
      const response = await request(`${host}/api/m3u/accounts/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve M3U accounts', e);
    }
  }

  static async addPlaylist(values) {
    if (values.custom_properties) {
      values.custom_properties = JSON.stringify(values.custom_properties);
    }

    try {
      let body = null;
      if (values.file) {
        body = new FormData();
        for (const prop in values) {
          body.append(prop, values[prop]);
        }
      } else {
        body = { ...values };
        delete body.file;
      }

      const response = await request(`${host}/api/m3u/accounts/`, {
        method: 'POST',
        body,
      });

      usePlaylistsStore.getState().addPlaylist(response);

      return response;
    } catch (e) {
      errorNotification('Failed to create M3U account', e);
    }
  }

  static async refreshPlaylist(id) {
    try {
      const response = await request(`${host}/api/m3u/refresh/${id}/`, {
        method: 'POST',
      });

      return response;
    } catch (e) {
      errorNotification('Failed to refresh M3U account', e);
    }
  }

  static async refreshAllPlaylist() {
    try {
      const response = await request(`${host}/api/m3u/refresh/`, {
        method: 'POST',
      });

      return response;
    } catch (e) {
      errorNotification('Failed to refresh all M3U accounts', e);
    }
  }

  static async deletePlaylist(id) {
    try {
      await request(`${host}/api/m3u/accounts/${id}/`, {
        method: 'DELETE',
      });

      usePlaylistsStore.getState().removePlaylists([id]);
      // @TODO: MIGHT need to optimize this later if someone has thousands of channels
      // but I'm feeling laze right now
      // useChannelsStore.getState().fetchChannels();
    } catch (e) {
      errorNotification(`Failed to delete playlist ${id}`, e);
    }
  }

  static async updatePlaylist(values, isToggle = false) {
    const { id, ...payload } = values;

    try {
      // If this is just toggling the active state, make a simpler request
      if (
        isToggle &&
        'is_active' in payload &&
        Object.keys(payload).length === 1
      ) {
        const response = await request(`${host}/api/m3u/accounts/${id}/`, {
          method: 'PATCH',
          body: { is_active: payload.is_active },
        });

        usePlaylistsStore.getState().updatePlaylist(response);
        return response;
      }

      // Original implementation for full updates
      let body = null;
      if (payload.file) {
        delete payload.server_url;

        body = new FormData();
        for (const prop in values) {
          body.append(prop, values[prop]);
        }
      } else {
        delete payload.file;
        if (!payload.server_url) {
          delete payload.sever_url;
        }

        body = { ...payload };
        delete body.file;
      }
      console.log(body);

      const response = await request(`${host}/api/m3u/accounts/${id}/`, {
        method: 'PATCH',
        body,
      });

      usePlaylistsStore.getState().updatePlaylist(response);

      return response;
    } catch (e) {
      errorNotification(`Failed to update M3U account ${id}`, e);
    }
  }

  static async getEPGs() {
    try {
      const response = await request(`${host}/api/epg/sources/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve EPGs', e);
    }
  }

  static async getEPGData() {
    try {
      const response = await request(`${host}/api/epg/epgdata/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve EPG data', e);
    }
  }

  // Notice there's a duplicated "refreshPlaylist" method above;
  // you might want to rename or remove one if it's not needed.

  static async addEPG(values) {
    try {
      let body = null;
      if (values.files) {
        body = new FormData();
        for (const prop in values) {
          body.append(prop, values[prop]);
        }
      } else {
        body = { ...values };
        delete body.file;
      }

      const response = await request(`${host}/api/epg/sources/`, {
        method: 'POST',
        body,
      });

      useEPGsStore.getState().addEPG(response);

      return response;
    } catch (e) {
      errorNotification('Failed to create EPG', e);
    }
  }

  static async updateEPG(values, isToggle = false) {
    const { id, ...payload } = values;

    try {
      // If this is just toggling the active state, make a simpler request
      if (
        isToggle &&
        'is_active' in payload &&
        Object.keys(payload).length === 1
      ) {
        const response = await request(`${host}/api/epg/sources/${id}/`, {
          method: 'PATCH',
          body: { is_active: payload.is_active },
        });

        useEPGsStore.getState().updateEPG(response);
        return response;
      }

      // Original implementation for full updates
      let body = null;
      if (payload.files) {
        body = new FormData();
        for (const prop in payload) {
          if (prop == 'url') {
            continue;
          }
          body.append(prop, payload[prop]);
        }
      } else {
        delete payload.file;
        if (!payload.url) {
          delete payload.url;
        }
        body = payload;
      }

      const response = await request(`${host}/api/epg/sources/${id}/`, {
        method: 'PATCH',
        body,
      });

      useEPGsStore.getState().updateEPG(response);

      return response;
    } catch (e) {
      errorNotification(`Failed to update EPG ${id}`, e);
    }
  }

  static async deleteEPG(id) {
    try {
      await request(`${host}/api/epg/sources/${id}/`, {
        method: 'DELETE',
      });

      useEPGsStore.getState().removeEPGs([id]);
    } catch (e) {
      errorNotification(`Failed to delete EPG ${id}`, e);
    }
  }

  static async refreshEPG(id) {
    try {
      const response = await request(`${host}/api/epg/import/`, {
        method: 'POST',
        body: { id },
      });

      return response;
    } catch (e) {
      errorNotification(`Failed to refresh EPG ${id}`, e);
    }
  }

  static async getStreamProfiles() {
    try {
      const response = await request(`${host}/api/core/streamprofiles/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve sream profiles', e);
    }
  }

  static async addStreamProfile(values) {
    try {
      const response = await request(`${host}/api/core/streamprofiles/`, {
        method: 'POST',
        body: values,
      });

      useStreamProfilesStore.getState().addStreamProfile(response);

      return response;
    } catch (e) {
      errorNotification('Failed to create stream profile', e);
    }
  }

  static async updateStreamProfile(values) {
    const { id, ...payload } = values;

    try {
      const response = await request(`${host}/api/core/streamprofiles/${id}/`, {
        method: 'PUT',
        body: payload,
      });

      useStreamProfilesStore.getState().updateStreamProfile(response);

      return response;
    } catch (e) {
      errorNotification(`Failed to update stream profile ${id}`, e);
    }
  }

  static async deleteStreamProfile(id) {
    try {
      await request(`${host}/api/core/streamprofiles/${id}/`, {
        method: 'DELETE',
      });

      useStreamProfilesStore.getState().removeStreamProfiles([id]);
    } catch (e) {
      errorNotification(`Failed to delete stream propfile ${id}`, e);
    }
  }

  static async getGrid() {
    try {
      const response = await request(`${host}/api/epg/grid/`);

      return response.data;
    } catch (e) {
      errorNotification('Failed to retrieve program grid', e);
    }
  }

  static async addM3UProfile(accountId, values) {
    try {
      const response = await request(
        `${host}/api/m3u/accounts/${accountId}/profiles/`,
        {
          method: 'POST',
          body: values,
        }
      );

      // Refresh the playlist
      const playlist = await API.getPlaylist(accountId);
      usePlaylistsStore
        .getState()
        .updateProfiles(playlist.id, playlist.profiles);

      return response;
    } catch (e) {
      errorNotification(`Failed to add profile to account ${accountId}`, e);
    }
  }

  static async deleteM3UProfile(accountId, id) {
    try {
      await request(`${host}/api/m3u/accounts/${accountId}/profiles/${id}/`, {
        method: 'DELETE',
      });

      const playlist = await API.getPlaylist(accountId);
      usePlaylistsStore.getState().updatePlaylist(playlist);
    } catch (e) {
      errorNotification(`Failed to delete profile for account ${accountId}`, e);
    }
  }

  static async updateM3UProfile(accountId, values) {
    const { id, ...payload } = values;

    try {
      await request(`${host}/api/m3u/accounts/${accountId}/profiles/${id}/`, {
        method: 'PUT',
        body: payload,
      });

      const playlist = await API.getPlaylist(accountId);
      usePlaylistsStore
        .getState()
        .updateProfiles(playlist.id, playlist.profiles);
    } catch (e) {
      errorNotification(`Failed to update profile for account ${accountId}`, e);
    }
  }

  static async getSettings() {
    try {
      const response = await request(`${host}/api/core/settings/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve settings', e);
    }
  }

  static async getEnvironmentSettings() {
    try {
      const response = await request(`${host}/api/core/settings/env/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve environment settings', e);
    }
  }

  static async getVersion() {
    try {
      const response = await request(`${host}/api/core/version/`, {
        auth: false,
      });

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve version', e);
    }
  }

  static async updateSetting(values) {
    const { id, ...payload } = values;

    try {
      const response = await request(`${host}/api/core/settings/${id}/`, {
        method: 'PUT',
        body: payload,
      });

      useSettingsStore.getState().updateSetting(response);

      return response;
    } catch (e) {
      errorNotification('Failed to update settings', e);
    }
  }

  static async getChannelStats(uuid = null) {
    try {
      const response = await request(`${host}/proxy/ts/status`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve channel stats', e);
    }
  }

  static async stopChannel(id) {
    try {
      const response = await request(`${host}/proxy/ts/stop/${id}`, {
        method: 'POST',
      });

      return response;
    } catch (e) {
      errorNotification('Failed to stop channel', e);
    }
  }

  static async stopClient(channelId, clientId) {
    try {
      const response = await request(
        `${host}/proxy/ts/stop_client/${channelId}`,
        {
          method: 'POST',
          body: { client_id: clientId },
        }
      );

      return response;
    } catch (e) {
      errorNotification('Failed to stop client', e);
    }
  }

  static async matchEpg() {
    try {
      const response = await request(
        `${host}/api/channels/channels/match-epg/`,
        {
          method: 'POST',
        }
      );

      return response;
    } catch (e) {
      errorNotification('Failed to run EPG auto-match', e);
    }
  }

  static async getLogos() {
    try {
      const response = await request(`${host}/api/channels/logos/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve logos', e);
    }
  }

  static async uploadLogo(file) {
    try {
      const formData = new FormData();
      formData.append('file', file);

      const response = await request(`${host}/api/channels/logos/upload/`, {
        method: 'POST',
        body: formData,
      });

      useChannelsStore.getState().addLogo(response);

      return response;
    } catch (e) {
      errorNotification('Failed to upload logo', e);
    }
  }

  static async getChannelProfiles() {
    try {
      const response = await request(`${host}/api/channels/profiles/`);

      return response;
    } catch (e) {
      errorNotification('Failed to get channel profiles', e);
    }
  }

  static async addChannelProfile(values) {
    try {
      const response = await request(`${host}/api/channels/profiles/`, {
        method: 'POST',
        body: values,
      });

      useChannelsStore.getState().addProfile(response);

      return response;
    } catch (e) {
      errorNotification('Failed to create channel profile', e);
    }
  }

  static async updateChannelProfile(values) {
    const { id, ...payload } = values;

    try {
      const response = await request(`${host}/api/channels/profiles/${id}/`, {
        method: 'PUT',
        body: payload,
      });

      useChannelsStore.getState().updateProfile(response);

      return response;
    } catch (e) {
      errorNotification('Failed to update channel profile', e);
    }
  }

  static async deleteChannelProfile(id) {
    try {
      await request(`${host}/api/channels/profiles/${id}/`, {
        method: 'DELETE',
      });

      useChannelsStore.getState().removeProfiles([id]);
    } catch (e) {
      errorNotification(`Failed to delete channel profile ${id}`, e);
    }
  }

  static async updateProfileChannel(channelId, profileId, enabled) {
    try {
      await request(
        `${host}/api/channels/profiles/${profileId}/channels/${channelId}/`,
        {
          method: 'PATCH',
          body: { enabled },
        }
      );

      useChannelsStore
        .getState()
        .updateProfileChannels([channelId], profileId, enabled);
    } catch (e) {
      errorNotification(`Failed to update channel for profile ${profileId}`, e);
    }
  }

  static async updateProfileChannels(channelIds, profileId, enabled) {
    try {
      await request(
        `${host}/api/channels/profiles/${profileId}/channels/bulk-update/`,
        {
          method: 'PATCH',
          body: {
            channels: channelIds.map((id) => ({
              channel_id: id,
              enabled,
            })),
          },
        }
      );

      useChannelsStore
        .getState()
        .updateProfileChannels(channelIds, profileId, enabled);
    } catch (e) {
      errorNotification(
        `Failed to bulk update channels for profile ${profileId}`,
        e
      );
    }
  }

  static async getRecordings() {
    try {
      const response = await request(`${host}/api/channels/recordings/`);

      return response;
    } catch (e) {
      errorNotification('Failed to retrieve recordings', e);
    }
  }

  static async createRecording(values) {
    try {
      const response = await request(`${host}/api/channels/recordings/`, {
        method: 'POST',
        body: values,
      });

      useChannelsStore.getState().fetchRecordings();

      return response;
    } catch (e) {
      errorNotification('Failed to create recording', e);
    }
  }

  static async deleteRecording(id) {
    try {
      await request(`${host}/api/channels/recordings/${id}/`, {
        method: 'DELETE',
      });

      useChannelsStore.getState().fetchRecordings();
    } catch (e) {
      errorNotification(`Failed to delete recording ${id}`, e);
    }
  }

  static async switchStream(channelId, streamId) {
    try {
      const response = await request(
        `${host}/proxy/ts/change_stream/${channelId}`,
        {
          method: 'POST',
          body: { stream_id: streamId },
        }
      );

      return response;
    } catch (e) {
      errorNotification('Failed to switch stream', e);
      throw e;
    }
  }

  static async nextStream(channelId, streamId) {
    try {
      const response = await request(
        `${host}/proxy/ts/next_stream/${channelId}`,
        {
          method: 'POST',
          body: { stream_id: streamId },
        }
      );

      return response;
    } catch (e) {
      errorNotification('Failed to switch stream', e);
      throw e;
    }
  }

  static async batchSetEPG(associations) {
    try {
      const response = await request(
        `${host}/api/channels/channels/batch-set-epg/`,
        {
          method: 'POST',
          body: { associations },
        }
      );

      // If successful, requery channels to update UI
      if (response.success) {
        notifications.show({
          title: 'EPG Association',
          message: `Updated ${response.channels_updated} channels, refreshing ${response.programs_refreshed} EPG sources.`,
          color: 'blue',
        });

        // First fetch the complete channel data
        await useChannelsStore.getState().fetchChannels();
        // Then refresh the current table view
        this.requeryChannels();
      }

      return response;
    } catch (e) {
      errorNotification('Failed to update channel EPGs', e);
    }
  }

  static async getChannel(id) {
    try {
      const response = await request(
        `${host}/api/channels/channels/${id}/?include_streams=true`
      );
      return response;
    } catch (e) {
      errorNotification('Failed to fetch channel details', e);
      return null;
    }
  }
}
