/*
This file is part of the Notesnook project (https://notesnook.com/)

Copyright (C) 2023 Streetwriters (Private) Limited

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
import { Note, NoteContent } from "@notesnook/core";
import { useThemeColors } from "@notesnook/theme";
import React, {
  RefObject,
  useCallback,
  useEffect,
  useLayoutEffect,
  useRef,
  useState
} from "react";
import { Linking, Platform, TextInput, View, ViewStyle } from "react-native";
import { WebView } from "react-native-webview";
import {
  ShouldStartLoadRequest,
  WebViewMessageEvent
} from "react-native-webview/lib/WebViewTypes";
import { eSubscribeEvent, eUnSubscribeEvent } from "../services/event-manager";
import { eOnLoadNote } from "../utils/events";
import { defaultBorderRadius } from "../utils/size";

const EditorMobileSourceUrl =
  Platform.OS === "android"
    ? "file:///android_asset/plaineditor.html"
    : "extension.bundle/plaineditor.html";
/**
 * Replace this with dev url when debugging or working on the editor mobile repo.
 * The url should be something like this: http://192.168.100.126:3000/index.html
 */
export const EDITOR_URI = __DEV__
  ? EditorMobileSourceUrl
  : EditorMobileSourceUrl;

export async function post(
  ref: RefObject<any>,
  type: string,
  value: any = null
) {
  const message = {
    type,
    value
  };
  setImmediate(() => ref.current?.postMessage(JSON.stringify(message)));
}

const useEditor = () => {
  const ref = useRef<WebView>(null);
  const { colors } = useThemeColors("editor");
  const currentNote = useRef<
    Note & {
      content: NoteContent<false>;
    }
  >(undefined);

  const postMessage = useCallback(
    async (type: string, data: any) => post(ref, type, data),
    []
  );

  const loadNote = useCallback(
    (
      note: Note & {
        content: NoteContent<false>;
      }
    ) => {
      postMessage("html", note.content.data);
      currentNote.current = note;
    },
    [postMessage]
  );

  useEffect(() => {
    eSubscribeEvent(eOnLoadNote + "shareEditor", loadNote);
    return () => {
      eUnSubscribeEvent(eOnLoadNote + "shareEditor", loadNote);
    };
  }, [loadNote]);

  const onLoad = () => {
    setTimeout(() => {
      postMessage(
        "theme",
        `
          body * {
            color: ${colors.primary.paragraph};
          }
  
          h1,
          h2,
          h3,
          h4,
          h5,
          h6 {
            color: ${colors.primary.heading};
          }
  
          a {
            color: ${colors.primary.accent};
          }
        `
      );
    }, 1);
  };

  return { ref, onLoad, currentNote };
};

const useEditorEvents = (
  editor: ReturnType<typeof useEditor>,
  onChange: (data: string) => void
) => {
  const onMessage = (event: WebViewMessageEvent) => {
    const data = event.nativeEvent.data;
    const editorMessage = JSON.parse(data);

    switch (editorMessage.type) {
      case "content":
        onChange(editorMessage.value);
        break;
    }
  };
  return onMessage;
};

const onShouldStartLoadWithRequest = (request: ShouldStartLoadRequest) => {
  if (request.url.includes("https")) {
    if (Platform.OS === "ios" && !request.isTopFrame) return true;
    Linking.openURL(request.url);
    return false;
  } else {
    return true;
  }
};

const style: ViewStyle = {
  height: "100%",
  maxHeight: "100%",
  width: "100%",
  alignSelf: "center",
  backgroundColor: "transparent"
};

export type EditorRef = {
  focus: () => void;
};

export const Editor = ({
  onChange,
  onLoad,
  editorRef
}: {
  onChange: (data: string) => void;
  onLoad: () => void;
  editorRef: RefObject<EditorRef | null>;
}) => {
  const { colors } = useThemeColors();
  const editor = useEditor();
  const inputRef = useRef<TextInput>(null);
  const onMessage = useEditorEvents(editor, onChange);
  const [loading, setLoading] = useState(true);
  useLayoutEffect(() => {
    onLoad?.();
  }, [onLoad]);

  useEffect(() => {
    if (editorRef) {
      editorRef.current = {
        focus: () => {
          setTimeout(() => {
            inputRef.current?.focus();
            editor.ref.current?.injectJavaScript(`(() => {
            const editor = document.getElementById('editor');
            if (editor) {
              editor.focus();
            }
          })();`);
            editor.ref?.current?.requestFocus();
          });
        }
      };
    }
  }, [editor.ref, editorRef]);

  return (
    <View
      style={{
        flex: 1
      }}
    >
      <TextInput
        ref={inputRef}
        style={{
          width: 1,
          height: 1,
          position: "absolute",
          zIndex: -1
        }}
      />
      <WebView
        ref={editor.ref}
        onLoad={() => {
          editor.onLoad();
          setTimeout(() => {
            setLoading(false);
            onLoad?.();
          }, 1);
        }}
        nestedScrollEnabled
        javaScriptEnabled={true}
        setSupportMultipleWindows={false}
        overScrollMode="never"
        scrollEnabled={Platform.OS === "ios"}
        keyboardDisplayRequiresUserAction={false}
        cacheMode="LOAD_DEFAULT"
        cacheEnabled={true}
        domStorageEnabled={true}
        bounces={false}
        setBuiltInZoomControls={false}
        setDisplayZoomControls={false}
        allowFileAccess={true}
        scalesPageToFit={true}
        hideKeyboardAccessoryView={false}
        allowsFullscreenVideo={true}
        allowFileAccessFromFileURLs={true}
        allowUniversalAccessFromFileURLs={true}
        onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
        originWhitelist={["*"]}
        source={{
          uri: EDITOR_URI
        }}
        style={style}
        autoManageStatusBarEnabled={false}
        onMessage={onMessage || undefined}
      />
      {loading ? (
        <View
          style={{
            position: "absolute",
            width: "100%",
            height: "100%",
            backgroundColor: colors.primary.background,
            alignItems: "flex-start",
            zIndex: 999,
            paddingHorizontal: 12
          }}
        >
          <View
            style={{
              height: 16,
              width: "100%",
              backgroundColor: colors.secondary.background,
              borderRadius: defaultBorderRadius,
              marginTop: 10
            }}
          />

          <View
            style={{
              height: 16,
              width: "100%",
              backgroundColor: colors.secondary.background,
              borderRadius: defaultBorderRadius,
              marginTop: 10
            }}
          />

          <View
            style={{
              height: 16,
              width: "60%",
              backgroundColor: colors.secondary.background,
              borderRadius: defaultBorderRadius,
              marginTop: 10
            }}
          />
        </View>
      ) : null}
    </View>
  );
};
