import { createSelector } from "reselect";
import lbryuri from "lbryuri";

const _selectState = state => state.claims || {};

export const selectClaimsById = createSelector(
  _selectState,
  state => state.byId || {}
);

export const selectClaimsByUri = createSelector(
  _selectState,
  selectClaimsById,
  (state, byId) => {
    const byUri = state.claimsByUri || {};
    const claims = {};

    Object.keys(byUri).forEach(uri => {
      const claimId = byUri[uri];

      // NOTE returning a null claim allows us to differentiate between an
      // undefined (never fetched claim) and one which just doesn't exist. Not
      // the cleanest solution but couldn't think of anything better right now
      if (claimId === null) {
        claims[uri] = null;
      } else {
        const claim = byId[claimId];

        claims[uri] = claim;
      }
    });

    return claims;
  }
);

export const selectAllClaimsByChannel = createSelector(
  _selectState,
  state => state.claimsByChannel || {}
);

const selectClaimForUri = (state, props) => {
  const uri = lbryuri.normalize(props.uri);
  return selectClaimsByUri(state)[uri];
};

export const makeSelectClaimForUri = () => {
  return createSelector(selectClaimForUri, claim => claim);
};

const selectClaimForUriIsMine = (state, props) => {
  const uri = lbryuri.normalize(props.uri);
  const claim = selectClaimsByUri(state)[uri];
  const myClaims = selectMyClaimsRaw(state);

  return myClaims.has(claim.claim_id);
};

export const makeSelectClaimForUriIsMine = () => {
  return createSelector(selectClaimForUriIsMine, isMine => isMine);
};

export const selectClaimsInChannelForUri = (state, props) => {
  return selectAllClaimsByChannel(state)[props.uri];
};

export const makeSelectClaimsInChannelForUri = () => {
  return createSelector(selectClaimsInChannelForUri, claims => claims);
};

const selectMetadataForUri = (state, props) => {
  const claim = selectClaimForUri(state, props);
  const metadata =
    claim && claim.value && claim.value.stream && claim.value.stream.metadata;

  const value = metadata ? metadata : claim === undefined ? undefined : null;
  return value;
};

export const makeSelectMetadataForUri = () => {
  return createSelector(selectMetadataForUri, metadata => metadata);
};

const selectSourceForUri = (state, props) => {
  const claim = selectClaimForUri(state, props);
  const source =
    claim && claim.value && claim.value.stream && claim.value.stream.source;

  return source ? source : claim === undefined ? undefined : null;
};

export const makeSelectSourceForUri = () => {
  return createSelector(selectSourceForUri, source => source);
};

export const makeSelectContentTypeForUri = () => {
  return createSelector(
    selectSourceForUri,
    source => (source ? source.contentType : source)
  );
};

export const selectIsFetchingClaimListMine = createSelector(
  _selectState,
  state => !!state.isFetchingClaimListMine
);

export const selectMyClaimsRaw = createSelector(
  _selectState,
  state => new Set(state.myClaims)
);

export const selectAbandoningIds = createSelector(_selectState, state =>
  Object.keys(state.abandoningById || {})
);

export const selectPendingClaims = createSelector(_selectState, state =>
  Object.values(state.pendingById || {})
);

export const selectMyClaims = createSelector(
  selectMyClaimsRaw,
  selectClaimsById,
  selectAbandoningIds,
  selectPendingClaims,
  (myClaimIds, byId, abandoningIds, pendingClaims) => {
    const claims = [];

    myClaimIds.forEach(id => {
      const claim = byId[id];

      if (claim && abandoningIds.indexOf(id) == -1) claims.push(claim);
    });

    return [...claims, ...pendingClaims];
  }
);

export const selectMyClaimsWithoutChannels = createSelector(
  selectMyClaims,
  myClaims => myClaims.filter(claim => !claim.name.match(/^@/))
);

export const selectMyClaimsOutpoints = createSelector(
  selectMyClaims,
  myClaims => {
    const outpoints = [];

    myClaims.forEach(claim => outpoints.push(`${claim.txid}:${claim.nout}`));

    return outpoints;
  }
);

export const selectFetchingMyChannels = createSelector(
  _selectState,
  state => !!state.fetchingMyChannels
);

export const selectMyChannelClaims = createSelector(
  _selectState,
  selectClaimsById,
  (state, byId) => {
    const ids = state.myChannelClaims || [];
    const claims = [];

    ids.forEach(id => claims.push(byId[id]));

    return claims;
  }
);