import { Component } from "react";
import codePush from "react-native-code-push";
import { GenericErrorScreen } from "./App/Container/Navi-Insurance";
import {
  AnalyticsEventNameConstants,
  BundleState,
  CODEPUSH_METHOD,
  EVENT_NAMES,
  EVENT_PROPERTY_KEYS,
  EVENT_PROPERTY_VALUES,
} from "./App/common/constants";
import { sendAsAnalyticsEvent } from "./App/common/hooks/useAnalyticsEvent";
import { CtaData } from "./App/common/interface";
import RnApp from "./App/common/navigator/RnAppCreator";
import {
  getBuildConfigDetailsFromCta,
  setBuildConfigDetailsFromCta,
} from "./App/common/utilities/CacheUtils";
import { initSentry } from "./App/common/utilities/SentryUtils";
import {
  getStringPreference,
  setStringPreference,
} from "./App/common/utilities/SharedPreferenceUtils";

interface AppState {
  bundleState: BundleState;
}

const preloadBundle: string = "PreloadBundle";

export default class App extends Component<{}, AppState> {
  constructor(props: {}) {
    super(props);
    initSentry(getBuildConfigDetailsFromCta(this.getInitialCta()!!).flavor);
    let bundleState = BundleState.LOADING;
    getBundleStatus().then(value => (bundleState = value));
    this.state = {
      bundleState: bundleState,
    };
  }
  checkForUpdates = async () => {
    const cta = this.getInitialCta();
    await setBuildConfigDetailsFromCta(cta!!);
    await codePush.sync(
      {
        installMode:
          cta?.title === preloadBundle
            ? codePush.InstallMode.IMMEDIATE
            : codePush.InstallMode.ON_NEXT_RESTART,
        mandatoryInstallMode: codePush.InstallMode.IMMEDIATE,
      },
      status => {
        this.onCodepushStatusChange(status);
      },
    );
  };

  onCodepushStatusChange = (status: codePush.SyncStatus) => {
    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);
        sendAsAnalyticsEvent({
          name: AnalyticsEventNameConstants.HI_RN_CODEPUSH_ERROR,
          properties: {
            errorType: EVENT_NAMES.CODEPUSH_IGNORED_ERROR,
            error: `${status}`,
            methodName: `${CODEPUSH_METHOD}`,
          },
        });
        break;
      case codePush.SyncStatus.UNKNOWN_ERROR:
        this.setState({ bundleState: BundleState.ERROR });
        sendAsAnalyticsEvent({
          name: EVENT_NAMES.CODEPUSH_FETCH_ERROR,
          properties: {
            [EVENT_PROPERTY_KEYS.STATUS]: EVENT_PROPERTY_VALUES.UNKNOWN_ERROR,
          },
        });
        sendAsAnalyticsEvent({
          name: AnalyticsEventNameConstants.HI_RN_CODEPUSH_ERROR,
          properties: {
            errorType: EVENT_NAMES.CODEPUSH_FAILED_ERROR,
            error: `${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) {
      sendAsAnalyticsEvent({
        name: AnalyticsEventNameConstants.HI_INVALID_SCREEN_CTA,
        properties: {
          errorType: EVENT_NAMES.CTA_MISSING_ERROR,
          error: `${CtaData}`,
          methodName: "getInitialCta",
        },
      });
      return;
    }

    try {
      const cta = JSON.parse(CtaData) as CtaData;
      return cta;
    } catch (error) {
      sendAsAnalyticsEvent({
        name: AnalyticsEventNameConstants.HI_INVALID_SCREEN_CTA,
        properties: {
          errorType: EVENT_NAMES.CTA_PARSING_ERROR,
          error: `${error}`,
          methodName: "getInitialCta",
        },
      });
      return;
    }
  };

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

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

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

    if (cta?.title === preloadBundle) {
      return <></>;
    } else if (!!cta) {
      return RnApp.create(cta);
    } else {
      sendAsAnalyticsEvent({
        name: EVENT_NAMES.INVALID_SCREEN_CTA,
      });
      return <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");
};
