import type {
  ApiSavedStarGift,
  ApiStarGiftAuctionState,
  ApiStarGiftAuctionUserState,
  ApiTypeStarGiftAuctionState,
} from '../../api/types';
import type { GlobalState } from '../types';

import { getCurrentTabId } from '../../util/establishMultitabRole';
import { omit, unique } from '../../util/iteratees';
import { updateTabState } from './tabs';

export function removeGiftInfoOriginalDetails<T extends GlobalState>(
  global: T,
  tabId: number = getCurrentTabId(),
): T {
  const tabState = global.byTabId[tabId];
  const { giftInfoModal } = tabState;
  if (!giftInfoModal) {
    return global;
  }

  const typeGift = giftInfoModal.gift;
  const isSavedGift = typeGift && 'gift' in typeGift;

  if (!isSavedGift) {
    return global;
  }

  const savedGift = typeGift;
  const innerGift = savedGift.gift;

  if (innerGift.type !== 'starGiftUnique') {
    return global;
  }

  const updatedInnerGift = {
    ...innerGift,
    attributes: innerGift.attributes?.filter((attr) => attr.type !== 'originalDetails'),
  };

  const updatedGift: ApiSavedStarGift = {
    ...savedGift,
    dropOriginalDetailsStars: undefined,
    gift: updatedInnerGift,
  };

  return updateTabState(global, {
    giftInfoModal: {
      ...giftInfoModal,
      gift: updatedGift,
    },
  }, tabId);
}

function getAuctionStateVersion(state: ApiTypeStarGiftAuctionState): number {
  return state.type === 'active' ? state.version : 0;
}

export function updateGiftAuction<T extends GlobalState>(
  global: T,
  auctionState: ApiStarGiftAuctionState,
): T {
  const giftId = auctionState.gift.id;
  const currentAuction = global.giftAuctionByGiftId?.[giftId];

  if (!currentAuction) return global;

  const serverVersion = getAuctionStateVersion(auctionState.state);
  const clientVersion = getAuctionStateVersion(currentAuction.state);

  if (serverVersion >= clientVersion) {
    return {
      ...global,
      giftAuctionByGiftId: {
        ...global.giftAuctionByGiftId,
        [giftId]: {
          ...auctionState,
          // Keep timeout in case of updates from active auction list, as those do not have this field
          timeout: auctionState.timeout || currentAuction.timeout,
        },
      },
    };
  }

  return global;
}

export function updateGiftAuctionState<T extends GlobalState>(
  global: T,
  giftId: string,
  state: ApiTypeStarGiftAuctionState,
): T {
  const giftAuction = global.giftAuctionByGiftId?.[giftId];

  if (!giftAuction) {
    return global;
  }

  const serverVersion = getAuctionStateVersion(state);
  const clientVersion = getAuctionStateVersion(giftAuction.state);

  if (serverVersion > clientVersion) {
    return {
      ...global,
      giftAuctionByGiftId: {
        ...global.giftAuctionByGiftId,
        [giftId]: {
          ...giftAuction,
          state,
        },
      },
    };
  }

  return global;
}

export function updateGiftAuctionUserState<T extends GlobalState>(
  global: T,
  giftId: string,
  userState: ApiStarGiftAuctionUserState,
): T {
  const giftAuction = global.giftAuctionByGiftId?.[giftId];

  if (!giftAuction) {
    return global;
  }

  const currentBidDate = giftAuction.userState.bidDate;
  if (userState.bidDate !== currentBidDate) {
    if (userState.bidDate) {
      global = {
        ...global,
        activeGiftAuctionIds: unique([...(global.activeGiftAuctionIds || []), giftId]),
      };
    } else {
      global = {
        ...global,
        activeGiftAuctionIds: global.activeGiftAuctionIds?.filter((id) => id !== giftId),
      };
    }
  }

  return {
    ...global,
    giftAuctionByGiftId: {
      ...global.giftAuctionByGiftId,
      [giftId]: {
        ...giftAuction,
        userState,
      },
    },
  };
}

export function replaceGiftAuction<T extends GlobalState>(
  global: T,
  auctionState: ApiStarGiftAuctionState,
): T {
  const giftId = auctionState.gift.id;

  const previousAuction = global.giftAuctionByGiftId?.[giftId];
  if (previousAuction) {
    if (previousAuction.userState.bidDate !== auctionState.userState.bidDate) {
      if (auctionState.userState.bidDate) {
        global = {
          ...global,
          activeGiftAuctionIds: unique([...(global.activeGiftAuctionIds || []), giftId]),
        };
      } else {
        global = {
          ...global,
          activeGiftAuctionIds: global.activeGiftAuctionIds?.filter((id) => id !== giftId),
        };
      }
    }
  }

  return {
    ...global,
    giftAuctionByGiftId: {
      ...global.giftAuctionByGiftId,
      [giftId]: {
        ...auctionState,
        timeout: auctionState.timeout || previousAuction?.timeout,
      },
    },
  };
}

export function removeGiftAuction<T extends GlobalState>(
  global: T,
  giftId: string,
): T {
  if (!global.giftAuctionByGiftId?.[giftId]) {
    return global;
  }

  const rest = omit(global.giftAuctionByGiftId, [giftId]);
  const activeGiftAuctionIds = global.activeGiftAuctionIds?.filter((id) => id !== giftId);

  return {
    ...global,
    giftAuctionByGiftId: Object.keys(rest).length ? rest : undefined,
    activeGiftAuctionIds,
  };
}
