import { init } from "@sentry/react-native";
import { Component } from "react";
import codePush from "react-native-code-push";
import {
  BundleState,
  CODEPUSH_METHOD,
  SentryConstants,
} from "./App/common/constants";
import { logToSentry } from "./App/common/hooks/useSentryLogging";
import { CtaData } from "./App/common/interface";
import RnApp from "./App/common/navigator/RnAppCreator";
import {
  getBuildConfigDetails,
  setBuildConfigDetails,
} from "./App/common/utilities/CacheUtils";
import {
  GenericErrorScreen,
  GenericShimmerScreen,
} from "./App/Container/Navi-Insurance";
import {
  getStringPreference,
  setStringPreference,
} from "./App/common/utilities/SharedPreferenceUtils";
import { useAnalyticsEvent } from "./App/common/hooks/useAnalyticsEvent";
import {
  EVENT_NAMES,
  EVENT_PROPERTY_KEYS,
  EVENT_PROPERTY_VALUES,
} from "./App/common/constants";

init({
  dsn: SentryConstants.SENTRY_DSN,
  environment: SentryConstants.SENTRY_ENVIRONMENT_PRODUCTION,
});

interface AppState {
  bundleState: BundleState;
}

const preloadBundle: string = 'PreloadBundle';

export default class App extends Component<{}, AppState> {
  

  constructor(props: {}) {
    super(props);
    let bundleState = BundleState.LOADING;
    getBundleStatus().then(value => (bundleState = value));
    this.state = {
      bundleState: bundleState,
    };
  }
  checkForUpdates = async () => {
    let flavor: string | undefined;
    getBuildConfigDetails().then(res => {
      flavor = res?.baseUrl;
    });
    await codePush.sync(
      {
        installMode: codePush.InstallMode.IMMEDIATE,
        mandatoryInstallMode: codePush.InstallMode.IMMEDIATE,
      },
      status => {
        this.onCodepushStatusChange(status);
      },
    );
  };

  onCodepushStatusChange = (status: codePush.SyncStatus) => {
    const { sendAsAnalyticsEvent, sendAsGlobalErrorEvent } =
      useAnalyticsEvent();
    switch (status) {
      case codePush.SyncStatus.CHECKING_FOR_UPDATE:
      case codePush.SyncStatus.DOWNLOADING_PACKAGE:
      case codePush.SyncStatus.INSTALLING_UPDATE:
        this.setState({ bundleState: BundleState.LOADING });
        storeBundleStatus(BundleState.LOADING);
        break;
      case codePush.SyncStatus.UP_TO_DATE:
        this.setState({ bundleState: BundleState.LOADED });
        storeBundleStatus(BundleState.LOADED);
        break;
      case codePush.SyncStatus.UPDATE_IGNORED:
        this.setState({ bundleState: BundleState.LOADED });
        storeBundleStatus(BundleState.LOADED);
        logToSentry(
          `Codepush Ignored | Status: ${status} | MethodName: ${CODEPUSH_METHOD}`,
        );
        break;
      case codePush.SyncStatus.UNKNOWN_ERROR:
        this.setState({ bundleState: BundleState.ERROR });
        sendAsAnalyticsEvent({
          name: EVENT_NAMES.CODEPUSH_FETCH_ERROR,
          properties: new Map([
            [EVENT_PROPERTY_KEYS.STATUS, EVENT_PROPERTY_VALUES.UNKNOWN_ERROR],
          ]),
        });
        storeBundleStatus(BundleState.ERROR);
        logToSentry(
          `Codepush Failed | Status: ${status} | MethodName: ${CODEPUSH_METHOD}`,
        );
        break;
      default:
        this.setState({ bundleState: BundleState.LOADED });
        storeBundleStatus(BundleState.LOADED);
    }
  };

  override shouldComponentUpdate(
    nextProps: Readonly<{}>,
    nextState: Readonly<AppState>,
    _: any,
  ): boolean {
    return this.state.bundleState !== nextState.bundleState;
  }

  getInitialCta = (): CtaData | undefined => {
    const { CtaData } = this.props as any;

    if (!CtaData) {
      logToSentry(
        `CtaData is missing or invalid: ${CtaData} | MethodName: getInitialCta`,
      );
      return;
    }

    try {
      const cta = JSON.parse(CtaData) as CtaData;
      return cta;
    } catch (error) {
      logToSentry(
        `Error parsing CtaData: ${CtaData} | Error: ${error} | MethodName: getInitialCta`,
      );
      return;
    }
  };

  override componentDidMount(): void {
    this.checkForUpdates();
    setBuildConfigDetails();
  }

  override componentWillUnmount(): void {
    invalidateStatus(BundleState.LOADING);
  }

  override render() {
    const cta = this.getInitialCta();

    if (cta?.title === preloadBundle) {
      return <></>;
    }

    return !!cta && this.state.bundleState === BundleState.LOADED ? (
      RnApp.create(cta)
    ) : this.state.bundleState === BundleState.LOADING ? (
      <GenericShimmerScreen />
    ) : (
      <GenericErrorScreen />
    );
  }
}

const storeBundleStatus = (bundleState: string) => {
  return setStringPreference("reactBundleState", bundleState);
};

const invalidateStatus = (bundleState: string) => {
  return setStringPreference("reactBundleState", bundleState);
};

const getBundleStatus = async () => {
  return await getStringPreference("reactBundleState", "string");
};
