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

let cachedUserList: AccountName[] = [];

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

  let user: User | undefined;

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

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

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

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

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

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

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

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

      user = {
        AccountName: 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,
          ),
        },
        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.AccountName);

    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: AccountName]: GetParam} = {};

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

    await getUser(AccountName);
  }
}

setInterval(refreshUsers, 500);

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

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

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

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

  return myUser;
}

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

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

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

  return myUser;
}
/*
function getUserSelectorAccountName(
  AccountName: AccountName,
): AccountName {
  addUserToGetQueue(AccountName, GetParam.CACHE);

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

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

  return myUser;
} */

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

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