import {maxCachedUsers} from '@caj/configs/appNonSaveVar';
import {appNonSaveVarActions} from '@caj/configs/appNonSaveVarReducer';
import {UserId, XAuthorization} from '@caj/configs/types';
import {makeRequest, apiBackendRequest} from '@caj/helper/request';
import BigDataManager from '@caj/helper/storage/BigDataManager';
import {RootState, store} from '@caj/redux/store';
import {useSelector} from 'react-redux';
import {
  BasicUserProp,
  createUserProp,
  ProfilePicture,
  ProfilePictureType,
  SourceProp,
  User,
} from './types';

let cachedUserList: UserId[] = [];

async function getUser(
  UserId: UserId,
  save?: boolean,
): Promise<User | undefined> {
  if (UserId === 'none') {
    return undefined;
  }

  let user: User | undefined;

  let state = store.getState();
  let userIsInCache = false;

  {
    const usr = state.nonSaveVariables.cachedUsers[UserId];
    if (usr !== undefined) {
      user = usr;
      userIsInCache = true;
    }
  }

  if (UserId === state.appVariables.preferences.selectedAccount) {
    const usr = state.appVariables.preferences.accounts[UserId];

    if (usr !== undefined) {
      user = {
        AccountName: usr.AccountName,
        Description: usr.Description,
        FollowersCount: usr.FollowersCount,
        FollowingCount: usr.FollowingCount,
        lastUpdateTimestamp: usr.lastUpdateTimestamp,
        ProfilePicture: usr.ProfilePicture,
        UserId,
        Username: usr.Username,
        XpLevel: usr.XpLevel,
        XpPoints: usr.XpPoints,
      };
    }
  }

  if (user === undefined) {
    const usr = await BigDataManager.databases.users.getEntry(UserId);

    if (usr !== undefined && usr !== null) {
      let ProfilePicture = {
        lq:
          usr.ProfilePictureBinaryLQ.byteLength !== 0
            ? createUserProp(
                SourceProp.offline,
                new Blob([usr.ProfilePictureBinaryLQ]),
              )
            : createUserProp(SourceProp.online, undefined, usr.ProfilePicture),
        hq:
          usr.ProfilePictureBinaryHQ.byteLength !== 0
            ? createUserProp(
                SourceProp.offline,
                new Blob([usr.ProfilePictureBinaryHQ]),
              )
            : createUserProp(SourceProp.online, undefined, usr.ProfilePicture),
      };

      user = {
        AccountName: createUserProp(SourceProp.offline, usr.AccountName),
        Description: createUserProp(SourceProp.offline, usr.Description),
        FollowersCount: createUserProp(SourceProp.offline, usr.FollowersCount),
        FollowingCount: createUserProp(SourceProp.offline, usr.FollowingCount),
        lastUpdateTimestamp: usr.lastUpdateTimestamp,
        ProfilePicture,
        UserId,
        Username: createUserProp(SourceProp.offline, usr.Username),
        XpLevel: createUserProp(SourceProp.offline, usr.XpLevel),
        XpPoints: createUserProp(SourceProp.offline, usr.XpPoints),
      };
    }
  }

  if (user === undefined) {
    try {
      const resp = await makeRequest({
        path: apiBackendRequest.GET_USER_PROFILE,
        requestGET: {':userId': UserId},
        response: {
          AccountName: '',
          Description: '',
          FollowersCount: 0,
          FollowingCount: 0,
          Username: '',
          XpLevel: 0,
          XpPoints: 0,
          AvatarUrl: '',
        },
      });

      user = {
        AccountName: createUserProp(
          SourceProp.cached,
          resp.response.AccountName,
        ),
        Description: createUserProp(
          SourceProp.cached,
          resp.response.Description,
        ),
        FollowersCount: createUserProp(
          SourceProp.cached,
          resp.response.FollowersCount,
        ),
        FollowingCount: createUserProp(
          SourceProp.cached,
          resp.response.FollowingCount,
        ),
        lastUpdateTimestamp: Math.floor(new Date().getTime() / 1000),
        ProfilePicture: {
          lq: createUserProp(
            SourceProp.online,
            undefined,
            resp.response.AvatarUrl,
          ),
        },
        UserId,
        Username: createUserProp(SourceProp.offline, resp.response.Username),
        XpLevel: createUserProp(SourceProp.cached, resp.response.XpLevel),
        XpPoints: createUserProp(SourceProp.cached, resp.response.XpPoints),
      };

      //BigDataManager.setEntry('users', user);
    } catch (error: any) {
      console.error(error.status);
    }
  }

  if (userIsInCache === false && user !== undefined) {
    console.log('save in cache');
    store.dispatch(appNonSaveVarActions.setCachedUser(user));
    cachedUserList.push(user.UserId);

    if (cachedUserList.length > maxCachedUsers) {
      let usrId = cachedUserList[0];
      cachedUserList.shift();
      console.log('usrId', usrId);

      store.dispatch(appNonSaveVarActions.removeCachedUser(usrId));
    }
  }

  return user;
}

enum GetParam {
  CACHE = 0,
  SAVE,
}

let getUserList: {[key: UserId]: GetParam} = {};

async function refreshUsers() {
  for (let UserId in getUserList) {
    const param = getUserList[UserId];
    delete getUserList[UserId];

    await getUser(UserId);
  }
}

setInterval(refreshUsers, 1300);

function addUserToGetQueue(UserId: UserId, param: GetParam) {
  if (getUserList[UserId] === undefined) {
    getUserList[UserId] = param;
  } else if (getUserList[UserId] < param) {
    getUserList[UserId] = param;
  }
}

function getUserSelector(UserId: UserId) {
  addUserToGetQueue(UserId, GetParam.CACHE);

  const myUser = useSelector(
    (state: RootState) => state.nonSaveVariables.cachedUsers[UserId],
  );

  if (myUser === undefined) {
    return initUndefinedUser(UserId);
  }

  return myUser;
}

function getUserSelectorPicture(UserId: UserId): ProfilePicture {
  addUserToGetQueue(UserId, GetParam.CACHE);

  const myUser = useSelector(
    (state: RootState) =>
      state.nonSaveVariables.cachedUsers[UserId]?.ProfilePicture,
  );

  if (myUser === undefined) {
    return {
      lq: createUserProp(SourceProp.online),
      hq: createUserProp(SourceProp.online),
    };
  }

  return myUser;
}

function getUserSelectorAccountName(UserId: UserId): BasicUserProp<string> {
  addUserToGetQueue(UserId, GetParam.CACHE);

  const myUser = useSelector(
    (state: RootState) =>
      state.nonSaveVariables.cachedUsers[UserId]?.AccountName,
  );

  if (myUser === undefined) {
    return createUserProp(SourceProp.online);
  }

  return myUser;
}

function initUndefinedUser(UserId: UserId): User {
  return {
    AccountName: createUserProp(SourceProp.online),
    Description: createUserProp(SourceProp.online),
    FollowersCount: createUserProp(SourceProp.online),
    FollowingCount: createUserProp(SourceProp.online),
    lastUpdateTimestamp: 0,
    ProfilePicture: {
      lq: createUserProp(SourceProp.online),
      hq: createUserProp(SourceProp.online),
    },
    UserId,
    Username: createUserProp(SourceProp.online),
    XpLevel: createUserProp(SourceProp.online),
    XpPoints: createUserProp(SourceProp.online),
  };
}

const UserManager = {
  getUser,
  getUserSelector,
  getUserSelectorPicture,
  getUserSelectorAccountName,
};
export default UserManager;
