// imports
import React from 'react';
import { usePathname, useRouter } from 'next/navigation';

// locals
import Input from '../Input';
import Confirm from '../Confirm';
import Overlay from '../Overlay';
import ApiSignal from '../../signals/Api';
import { addSnack } from '../../signals/Snacks';
import { useBranches } from '../../data/useBranch';
import Signal, { useSignal } from '../../signal';
import { current as TeamSignal } from '../../signals/Teams';

// create character signal
export const remove   = new Signal.State(null);
export const update   = new Signal.State(false);
export const saving   = new Signal.State(false);
export const removing = new Signal.State(false);

// on remove
export const onRemove = new Signal.State(null);
export const onUpdate = new Signal.State(null);

/**
 * workflow globals
 */
const WorkflowGlobals = () => {
  // signals
  const [sApi] = useSignal(ApiSignal);
  const [sTeam] = useSignal(TeamSignal);
  const [sOnRemove] = useSignal(onRemove);
  const [sOnUpdate] = useSignal(onUpdate);
  const [sUpdate, setUpdate] = useSignal(update);
  const [sRemove, setRemove] = useSignal(remove);
  const [sSaving, setSaving] = useSignal(saving);
  const [sRemoving, setRemoving] = useSignal(removing);

  // router
  const path = usePathname();
  const router = useRouter();

  // branches
  const { branches } = useBranches({
    team     : sTeam?.id,
    workflow : sUpdate?.id,
  }, {
    disable : !sUpdate?.id || !sTeam?.id,
  });

  // on remove
  const handleRemove = async () => {
    // check saving
    if (sSaving) return;
    if (sRemoving) return;

    // set removing
    setRemoving(true);

    // try/catch
    try {
      // do save
      const removedWorkflow = await sApi.Workflow.delete(sRemove);

      // check result
      if (removedWorkflow?.message) {
        // @todo deal with errors
        return;
      }

      // if on remove
      if (sOnRemove) {
        sOnRemove(removedWorkflow);
      }

      // set remove
      setRemove(null);

      // router
      router.push(`/${sTeam?.id}/workflows`);
    } catch (e) {
      console.log(e);
    } finally {
      // saving
      setRemoving(false);
    }
  };

  /**
   * on save
   *
   * @param changes 
   */
  const handleSave = async (changes = {}) => {
    // check saving
    if (sSaving) return;
    if (sRemoving) return;
    
    // set saving
    setSaving(true);

    // try/catch
    try {
      // do save
      const newWorkflow = await sApi.Workflow[sUpdate?.id ? 'update' : 'create']({
        ...sUpdate,
        ...changes,
        team : sTeam?.id,
      });

      // check url
      if (!sUpdate.id) sUpdate.id = newWorkflow.workflow?.id;

      // check url
      if (!path.includes(`/${sTeam?.id}/workflows/${sUpdate?.id}`)) {
        // replace state in window history
        window?.history?.replaceState?.(null, '', `/${sTeam?.id}/workflows/${sUpdate?.id}`);
      }

      // check result
      if (newWorkflow?.message) {
        // add snack
        addSnack({
          id       : 'node.save.error',
          message  : sApi.translate(`workflow:validation.${newWorkflow.message}`),
          severity : 'error',
        });
        
        // @todo deal with errors
        return;
      }

      // loop all workflow nodes to set position
      (sUpdate?.nodes || []).forEach((subNode) => {
        // check node exists
        const exists = newWorkflow.workflow.nodes.find((n) => (n.id === subNode.id) || (n.temp === subNode.temp));

        // check exists
        if (!exists) return;

        // set position
        exists.id = subNode.id;
      });

      // set workflow
      if (sOnUpdate) {
        // set on update
        sOnUpdate(sUpdate);
      }
      
      // set update
      setUpdate(newWorkflow.workflow);
    } catch (e) {
      console.log(e);
    } finally {
      // saving
      setSaving(false);
    }
  };

  // return jsx
  return (
    <>

      <Confirm
        open={!!sRemove}
        title={sApi.translate('workflow:dialog.remove.title', sRemove)}
        onClose={() => setRemove(false)}
        loading={sRemoving}
        onConfirm={handleRemove}
        description={sApi.translate('workflow:dialog.remove.message', sRemove)}
      />
      <Overlay
        open={!!sUpdate}
        title={sApi.translate('workflow:dialog.update.title', sUpdate)}
        onClose={() => setUpdate(false)}
        loading={sSaving}
        onSubmit={() => handleSave()}
        subtitle={sApi.translate('workflow:dialog.update.message', sUpdate)}
      >
        <div className="flex flex-col pb-4 space-y-3 w-full">
          <Input
            label={sApi.translate('workflow:form.name.label')}
            value={sUpdate?.name || ''}
            placeholder={sApi.translate('workflow:form.name.placeholder')}
            onChange={(e) => {
              // changed
              const newWorkflow = {
                ...sUpdate,
                name : e.target.value,
              };
              
              // set workflow
              setUpdate(newWorkflow);

              // set changed
              if (sOnUpdate) {
                // set on update
                sOnUpdate(newWorkflow);
              }
            }}
          />
      
          <Input
            name="branch"
            type="select"
            label={sApi.translate('workflow:form.branch.label', 'Branch')}
            value={sUpdate?.branch || ''}
            onChange={(e) => setUpdate({
              ...sUpdate,
              branch : e.target.value,
            })}
            placeholder={sApi.translate('workflow:form.branch.placeholder', 'Select the branch')}
          >
            {branches.map(branch => (
              <option key={branch.id} value={branch.id}>
                {branch.name}
              </option>
            ))}
          </Input>

          {!!sUpdate?.code && (
            <div>
              <p className="mb-3 font-semibold">
                {sApi.translate('workflow:button.http')}
              </p>
              <div className="flex overflow-x-auto p-3 w-full text-sm rounded-xl bg-gray-900/10">
                <pre>
                  <code>
                    {`POST: ${process.env.API_URL}/v1/workflow/${sUpdate?.code}/run`}
                  </code>
                </pre>
              </div>
            </div>
          )}
        </div>
      </Overlay>

    </>
  );
};

/**
 * export default
 */
export default WorkflowGlobals;