import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import config, { SuccessOrFailType } from '../config/config';
import apiKeyInvalid from '../utils/apiKey';
import { IS_CHROME } from '../utils/operatingSystem';
import { getSettings, ProjectName, saveSettings, Settings } from '../utils/settings';
import { logUserIn } from '../utils/user';
import CustomProjectNameList from './CustomProjectNameList';
import SitesList from './SitesList';

interface State extends Settings {
  alertText: string;
  alertType: SuccessOrFailType;
  loading: boolean;
}

export default function Options(): JSX.Element {
  const [state, setState] = useState<State>({
    alertText: config.alert.success.text,
    alertType: config.alert.success.type,
    allowList: [],
    apiKey: '',
    apiUrl: config.apiUrl,
    customProjectNames: [],
    denyList: [],
    extensionStatus: 'allGood',
    hostname: '',
    loading: false,
    loggingEnabled: true,
    loggingStyle: config.loggingStyle,
    loggingType: config.loggingType,
    socialMediaSites: config.socialMediaSites,
    theme: config.theme,
    trackSocialMedia: config.trackSocialMedia,
  });

  const isApiKeyValid = useMemo(() => apiKeyInvalid(state.apiKey) === '', [state.apiKey]);

  const loggingStyleRef = useRef(null);

  const restoreSettings = useCallback(async () => {
    const settings = await getSettings();
    setState((oldState) => ({
      ...oldState,
      ...settings,
    }));
  }, []);

  useEffect(() => {
    void restoreSettings();
  }, [restoreSettings]);

  const handleSubmit = async () => {
    if (state.loading) return;
    setState((oldState) => ({ ...oldState, loading: true }));
    if (state.apiUrl.endsWith('/')) {
      state.apiUrl = state.apiUrl.slice(0, -1);
    }
    await saveSettings({
      allowList: state.allowList.filter((item) => !!item.trim()),
      apiKey: state.apiKey,
      apiUrl: state.apiUrl,
      customProjectNames: state.customProjectNames.filter(
        (item) => !!item.url.trim() && !!item.projectName.trim(),
      ),
      denyList: state.denyList.filter((item) => !!item.trim()),
      extensionStatus: state.extensionStatus,
      hostname: state.hostname,
      loggingEnabled: state.loggingEnabled,
      loggingStyle: state.loggingStyle,
      loggingType: state.loggingType,
      socialMediaSites: state.socialMediaSites.filter((item) => !!item.trim()),
      theme: state.theme,
      trackSocialMedia: state.trackSocialMedia,
    });
    setState(state);
    await logUserIn(state.apiKey);
    if (IS_CHROME) {
      window.close();
    }
  };

  const updateDenyListState = useCallback((denyList: string[]) => {
    setState((oldState) => ({
      ...oldState,
      denyList,
    }));
  }, []);

  const updateAllowListState = useCallback((allowList: string[]) => {
    setState((oldState) => ({
      ...oldState,
      allowList,
    }));
  }, []);

  const updateCustomProjectNamesState = useCallback((customProjectNames: ProjectName[]) => {
    setState((oldState) => ({
      ...oldState,
      customProjectNames,
    }));
  }, []);

  const updateLoggingStyle = useCallback((style: string) => {
    setState((oldState) => ({
      ...oldState,
      loggingStyle: style === 'allow' ? 'allow' : 'deny',
    }));
  }, []);

  const updateLoggingType = useCallback((type: string) => {
    setState((oldState) => ({
      ...oldState,
      loggingType: type === 'url' ? 'url' : 'domain',
    }));
  }, []);

  const updateTheme = useCallback((theme: string) => {
    setState((oldState) => ({
      ...oldState,
      theme: theme === 'light' ? 'light' : 'dark',
    }));
  }, []);

  const toggleSocialMedia = useCallback(() => {
    setState((oldState) => ({
      ...oldState,
      trackSocialMedia: !oldState.trackSocialMedia,
    }));
  }, []);

  const loggingStyle = useCallback(() => {
    // TODO: rewrite SitesList to be structured inputs instead of textarea

    if (state.loggingStyle == 'deny') {
      return (
        <SitesList
          handleChange={updateDenyListState}
          label="Exclude"
          sites={state.denyList}
          helpText="Sites that you don't want to show in your reports."
        />
      );
    }
    return (
      <SitesList
        handleChange={updateAllowListState}
        label="Include"
        sites={state.allowList}
        projectNamePlaceholder="http://google.com&#10;http://myproject.com/MyProject"
        helpText="Only track these sites."
      />
    );
  }, [
    state.allowList,
    state.denyList,
    state.loggingStyle,
    updateAllowListState,
    updateDenyListState,
  ]);

  return (
    <div className="container">
      <div className="row">
        <div className="col-md-12">
          <form className="form-horizontal">
            <div className="form-group mb-4">
              <label htmlFor="apiKey" className="form-label mb-0">
                API Key
              </label>
              <input
                id="apiKey"
                autoFocus={true}
                type="text"
                className={`form-control ${isApiKeyValid ? '' : 'is-invalid'}`}
                placeholder="API key"
                value={state.apiKey}
                onChange={(e) => setState({ ...state, apiKey: e.target.value })}
              />
            </div>

            <div className="form-group mb-4">
              <label htmlFor="loggingStyle" className="form-label">
                Logging style
              </label>
              <select
                id="loggingStyle"
                ref={loggingStyleRef}
                className="form-control"
                value={state.loggingStyle}
                onChange={(e) => updateLoggingStyle(e.target.value)}
              >
                <option value="deny">All except excluded sites</option>
                <option value="allow">Only allowed sites</option>
              </select>
            </div>

            {loggingStyle()}

            <div className="form-group mb-4">
              <label htmlFor="loggingType" className="form-label">
                Logging type
              </label>
              <select
                id="loggingType"
                className="form-control"
                value={state.loggingType}
                onChange={(e) => updateLoggingType(e.target.value)}
              >
                <option value="domain">Only the domain</option>
                <option value="url">Entire URL</option>
              </select>
            </div>

            <div className="form-group mb-4">
              <label htmlFor="selectTheme" className="form-label mb-0">
                Theme
              </label>
              <select
                id="selectTheme"
                className="form-control"
                value={state.theme}
                onChange={(e) => updateTheme(e.target.value)}
              >
                <option value="light">Light</option>
                <option value="dark">Dark</option>
              </select>
            </div>

            <div className="form-group mb-4">
              <label htmlFor="selectHost" className="form-label mb-0">
                Hostname
              </label>
              <input
                id="selectHost"
                type="text"
                className="form-control"
                value={state.hostname}
                onChange={(e) => setState({ ...state, hostname: e.target.value })}
              />
              <span className="text-secondary">
                Optional name of local machine. By default &apos;Unknown Hostname&apos;.
              </span>
            </div>

            <CustomProjectNameList
              sites={state.customProjectNames}
              label="Custom Project Names"
              handleChange={updateCustomProjectNamesState}
              helpText=""
            />

            <div className="form-group mb-4">
              <label htmlFor="apiUrl" className="form-label mb-0">
                API Url
              </label>

              <input
                id="apiUrl"
                type="text"
                className="form-control"
                value={state.apiUrl}
                onChange={(e) => setState({ ...state, apiUrl: e.target.value })}
                placeholder="https://api.wakatime.com/api/v1"
              />
              <span className="help-block">https://api.wakatime.com/api/v1</span>
            </div>

            <div className="form-group row mb-4">
              <div className="col-lg-10 col-lg-offset-2 space-between align-items-center">
                <div>
                  <input
                    type="checkbox"
                    className="me-2"
                    checked={state.trackSocialMedia}
                    onChange={toggleSocialMedia}
                  />
                  <span onClick={toggleSocialMedia}>Track social media sites</span>
                </div>
                <button
                  type="button"
                  className="btn btn-primary btn-sm"
                  data-bs-toggle="modal"
                  data-bs-target="#socialSitesModal"
                >
                  Sites
                </button>
                <div
                  className="modal fade"
                  id="socialSitesModal"
                  role="dialog"
                  aria-labelledby="socialSitesModalLabel"
                >
                  <div className="modal-dialog" role="document">
                    <div className="modal-content">
                      <div className="modal-header">
                        <h4 className="modal-title fs-5" id="socialSitesModalLabel">
                          Social Media Sites
                        </h4>
                        <button
                          type="button"
                          className="btn-close"
                          data-bs-dismiss="modal"
                          aria-label="Close"
                        />
                      </div>
                      <div className="modal-body">
                        <SitesList
                          handleChange={(socialMediaSites) => {
                            setState((oldState) => ({
                              ...oldState,
                              socialMediaSites,
                            }));
                          }}
                          label="Social"
                          sites={state.socialMediaSites}
                          helpText="Sites that you don't want to show in your reports."
                        />
                      </div>
                      <div className="modal-footer">
                        <button type="button" className="btn btn-primary" data-bs-dismiss="modal">
                          Close
                        </button>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>

            <div className="form-group mb-4">
              <div className="d-grid gap-2 col-6 ">
                <button
                  type="button"
                  className={`btn btn-primary ${state.loading ? 'disabled' : ''}`}
                  disabled={state.loading}
                  data-loading-text="Loading..."
                  onClick={handleSubmit}
                >
                  Save
                </button>
              </div>
            </div>
          </form>
        </div>
      </div>
    </div>
  );
}
