import React, {useCallback, useEffect, useState} from 'react';
import * as ReactDOM from 'react-dom/client';
import {
  SidebarButtonToggleStyle,
  SidebarCloseButtonStyle, SidebarDataOptionsStyle,
  SidebarHeaderStyle,
  SidebarStyle,
} from "./data-options.style.js";
import {isClickOutside, isEscHit} from "../responsive-button/ResponsiveButton.jsx";
import {DesignPreview} from "./DesignPreview.jsx";

export const PRODUCTION_REGISTRY_URL = 'https://blocks-registery.axe-web.com';

function DataOptions(props = {}) {
  props.rootAttributes = props.rootAttributes ?? {};

  const initialState = {
    dataName: 'default',
    data: {},
    dataText: '{}',
    dataOptions: [],
    designPreview: [],
    errorMessage: null,
    loading: false,
  };

  const [state, setState] = useState(initialState);
  const [previewOption, setPreviewOption] = useState(getDesignPreviewImage(state.dataName, state.designPreview));
  const updateState = (update) => setState(Object.assign({}, state, update));

  const [sidebarOpen, setSidebarOpen] = useState(false);

  useEffect(async () => {
    await syncDataOptions(state.dataName);
  }, []);

  const handleCloseSidebarEscEvent = useCallback((e) => {
    if (isEscHit(e)) {
      (() => {
        closeSidebar()
      })();
    }
  }, []);

  useEffect(() => {
    document.addEventListener("keydown", handleCloseSidebarEscEvent);

    // Unsubscribe from ESC listener.
    return () => {
      document.removeEventListener("keydown", handleCloseSidebarEscEvent);
    }
  }, [handleCloseSidebarEscEvent]);

  useEffect(() => {
    window.addEventListener('message', responsiveModeChangesHandler);
    return () => window.removeEventListener('message', responsiveModeChangesHandler);
  }, [state]);

  useEffect(() => {
    setPreviewOption(getDesignPreviewImage(state.dataName, state.designPreview));
  }, [state.designPreview]);

  const handleBlur = async (e) => await isClickOutside(e) ? closeSidebar() : null;

  return <div style={{display: 'flex', gap: '1rem', alignItems: 'center'}}>
    <SidebarButtonToggleStyle onClick={() => openSidebar()} title="Open a Sidebar with Data Options"/>

    <DesignPreview previewOption={previewOption}/>

    <SidebarStyle className={sidebarOpen ? 'active sidebar-active' : ''} tabIndex='0' onBlur={handleBlur}>
      <SidebarHeaderStyle>
        <SidebarCloseButtonStyle onClick={() => closeSidebar()}></SidebarCloseButtonStyle>
      </SidebarHeaderStyle>

      {state.dataOptions && !!state.dataOptions.length &&
        <SidebarDataOptionsStyle>
          <label htmlFor="data-options">Data Options</label>

          <select name="data" id="data-options" onChange={(e) => changeDataOption(e)} value={state.dataName} disabled={state.loading}>
            {state.dataOptions.map((item) => {
              const isSelected = state.dataName === item;
              return <option value={item} selected={isSelected}>{item}</option>
            })}
          </select>
        </SidebarDataOptionsStyle>
      }

      {state.data &&
        <textarea value={state.dataText} onChange={dataOptionUpdate} disabled={state.loading}/>
      }

      {state.errorMessage &&
        <p className={'alert alert--error'}>{state.errorMessage}</p>
      }

      {state.loading &&
        <p className={'alert'}>Loading, please wait...</p>
      }

      <div className={'actions'}>
        <button className='btn btn--secondary' disabled={state.loading} onClick={(e) => copyToClipboard(e, state.data)}>Copy to Clipboard</button>
        <button className='btn btn--secondary' disabled={state.loading} onClick={(e) => generateVariation(e, state.data)}>Generate Test</button>
      </div>
    </SidebarStyle>
  </div>;

  //
  // Functions
  //

  function generateVariation() {
    const url = PRODUCTION_REGISTRY_URL + '/content-generator/';

    const myHeaders = new Headers();
    myHeaders.append("Content-Type", "application/json");

    const requestOptions = {
      method: 'POST',
      headers: myHeaders,
      body: JSON.stringify({json: state.data}),
    };

    updateState({loading: true, errorMessage: null});

    return fetch(url, requestOptions)
      .then(response => response.json())
      .then(result => {
        console.log(result)
        if (result.statusCode !== 200) {
          throw new Error(result.message);
        }

        const data = result.variation;
        updateState({dataText: JSON.stringify(data, null, 2), data, errorMessage: null, loading: false});
        updateIframe(data);
      })
      .catch(error => {
        updateState({loading: false, errorMessage: 'Something went wrong, please try again.'})
      });

  }

  function dataOptionUpdate(e) {
    let data;

    try {
      data = JSON.parse(e.target.value);
    } catch (err) {
      updateState({dataText: e.target.value, errorMessage: 'Invalid JSON, please review and try again.'});
      return;
    }

    updateState({dataText: e.target.value, data, errorMessage: null});
    updateIframe(data);
  }

  function openSidebar() {
    setSidebarOpen(true);
    setTimeout(() => document.querySelector('.sidebar-active').focus());
  }

  function closeSidebar() {
    setSidebarOpen(false);
  }

  async function changeDataOption(e) {
    const dataName = e.target.value;
    await syncDataOptions(dataName);
  }

  async function fetchDataOptions(name = 'default') {
    const queryParameters = new URLSearchParams({name, block: window.devTool.blockName});
    const response = await fetch(`/data?${queryParameters}`);
    return await response.json();
  }

  function getDesignPreviewImage(currentDataName, designPreviewOptions = []) {
    const dataOptions = designPreviewOptions.filter((item) => {
      return item.dataSource === currentDataName;
    });

    dataOptions.sort((a, b) => b.widthDimension - a.widthDimension);
    let size = window.responsiveState.breakpoint;
    if (size === '100%') {
      size = window.innerWidth;
    }

    return dataOptions.find((item) => {
      return size >= item.widthDimension;
    });
  }

  function responsiveModeChangesHandler(e) {
    if (e.data !== 'responsiveUpdate') {
      return;
    }

    setPreviewOption(getDesignPreviewImage(state.dataName, state.designPreview));
  }

  async function syncDataOptions(dataName) {
    const dataOptions = await fetchDataOptions(dataName);
    updateIframe(dataOptions.data);

    const newState = Object.assign({errorMessage: null},
      dataOptions,
      {dataName},
      {dataText: JSON.stringify(dataOptions.data, null, 2)},
    );
    updateState(newState);
  }

  function updateIframe(data) {
    const previewIframe = props.rootAttributes.previewFrame;
    previewIframe.contentWindow.postMessage('dataUpdate:' + JSON.stringify(data || {}), '*');
  }
}

function copyToClipboard(e, context) {
  e.stopPropagation();

  if (typeof context !== 'string') {
    context = JSON.stringify(context, null, 2);
  }

  if (navigator.clipboard && window.isSecureContext) {
    // This case will not work on non-https pages.
    return navigator.clipboard.writeText(context);
  } else {
    let textArea = document.createElement("textarea");
    textArea.value = context;
    textArea.style.position = "fixed";
    textArea.style.left = "-999999px";
    textArea.style.top = "-999999px";
    document.body.appendChild(textArea);
    // textArea.focus();
    textArea.select();
    return new Promise((res, rej) => {
      document.execCommand('copy') ? res() : rej();
      textArea.remove();
      e.target.focus()
    });
  }
}

export function setupDataOptions(rootAttributes) {
  // INIT
  const wrapper = document.createElement('div');
  document.querySelector('.page_toolbar__left').prepend(wrapper)

  const root = ReactDOM.createRoot(wrapper);
  const html = (<DataOptions rootAttributes={rootAttributes}/>);
  root.render(html);
}
