import { useCallback, useEffect, useMemo, useState } from 'react';

import { PartRight, RESTConfig, UserMe, UserResource } from '@/back-api';
import { environment, getApiUrl } from '@/environment';
import { useServiceContext } from '@/service/ServiceContext';
import { SessionState } from '@/service/SessionState';
import { isBrowser } from '@/utils/layout';
import { parseToken } from '@/utils/sso';

const TOKEN_KEY = 'karusic-token-key-storage';

export const USERS = {
  admin:
    'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYXBwbGljYXRpb24iOiJrYXJ1c2ljIiwiaXNzIjoiS2FyQXV0aCIsInJpZ2h0Ijp7ImthcnVzaWMiOnsiQURNSU4iOnRydWUsIlVTRVIiOnRydWV9fSwibG9naW4iOiJIZWVyb1l1aSIsImV4cCI6MTcyNDIwNjc5NCwiaWF0IjoxNzI0MTY2ODM0fQ.TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E',
  NO_USER: '',
} as const;

export const getUserToken = () => {
  return localStorage.getItem(TOKEN_KEY);
};
export type RightPart = 'admin' | 'user';

export function getRestConfig(): RESTConfig {
  return {
    server: getApiUrl(),
    token: getUserToken() ?? '',
  };
}

export type SessionServiceProps = {
  token?: string;
  setToken: (token: string) => void;
  clearToken: () => void;
  login?: string;
  hasReadRight: (part: RightPart) => boolean;
  hasWriteRight: (part: RightPart) => boolean;
  state: SessionState;
  getRestConfig: () => RESTConfig;
};

export const useSessionService = (): SessionServiceProps => {
  const { session } = useServiceContext();
  return session;
};

export const useSessionServiceWrapped = (): SessionServiceProps => {
  const [token, setToken] = useState<string | undefined>(
    isBrowser ? (localStorage.getItem(TOKEN_KEY) ?? undefined) : undefined
  );
  const [state, setState] = useState<SessionState>(SessionState.NO_USER);
  const [config, setConfig] = useState<UserMe | undefined>(undefined);

  const updateRight = useCallback(() => {
    if (isBrowser) {
      console.log('Detect a new token...');
      setState(SessionState.NO_USER);
      setConfig(undefined);
      if (token === undefined) {
        console.log(`  ==> No User`);
        setState(SessionState.NO_USER);
        localStorage.removeItem(TOKEN_KEY);
      } else if (token === '__LOGOUT__') {
        console.log(`  ==> disconnection: ${token}`);
        setState(SessionState.DISCONNECT);
        localStorage.removeItem(TOKEN_KEY);
      } else if (!['__LOGOUT__', '__FAIL__', '__CANCEL__'].includes(token)) {
        console.log('  ==> Login ... (try to keep right)');
        setState(SessionState.CONNECTING);
        localStorage.setItem(TOKEN_KEY, token);
        UserResource.getMe({
          restConfig: getRestConfig(),
        })
          .then((response: UserMe) => {
            //console.log(`    ==> New right arrived to '${response.login}'`);
            setState(SessionState.CONNECTED);
            setConfig(response);
          })
          .catch((error) => {
            setState(SessionState.CONNECTION_FAIL);
            //console.log(`    ==> Fail to get right: '${error}'`);
            localStorage.removeItem(TOKEN_KEY);
          });
      }
    }
  }, [localStorage, parseToken, token]);
  const setTokenLocal = useCallback(
    (token: string) => {
      setToken(token);
      updateRight();
    },
    [updateRight, setToken]
  );
  const clearToken = useCallback(() => {
    setToken(undefined);
    updateRight();
  }, [updateRight, setToken]);
  const hasReadRight = useCallback(
    (part: RightPart) => {
      //console.log(`config = ${JSON.stringify(config, null, 2)}`);
      const right = config?.rights[environment.applName];
      if (right === undefined) {
        return false;
      }
      return [PartRight.READ, PartRight.READ_WRITE].includes(right[part]);
    },
    [config]
  );
  const hasWriteRight = useCallback(
    (part: RightPart) => {
      const right = config?.rights[environment.applName];
      if (right === undefined) {
        return false;
      }
      return [PartRight.READ, PartRight.READ_WRITE].includes(right[part]);
    },
    [config]
  );

  const getRestConfig = useCallback((): RESTConfig => {
    return {
      server: getApiUrl(),
      token: token ?? '',
    };
  }, [token]);

  useEffect(() => {
    updateRight();
  }, [updateRight]);

  return {
    token,
    setToken: setTokenLocal,
    clearToken,
    login: config?.login,
    hasReadRight,
    hasWriteRight,
    state,
    getRestConfig,
  };
};

export const useHasRight = (part: RightPart) => {
  const { token, hasReadRight, hasWriteRight } = useSessionService();
  const isReadable = useMemo(() => {
    console.log(`get is read for: ${part} ==> ${hasReadRight(part)}`);
    return hasReadRight(part);
  }, [token, hasReadRight, part]);
  const isWritable = useMemo(() => {
    return hasWriteRight(part);
  }, [token, hasWriteRight, part]);
  return { isReadable, isWritable };
};
