import {
  createEffect,
  createMemo,
  createResource,
  createSignal,
} from "solid-js";
import ListManager from "../components/list-manager.jsx";
import ValidatedTextInput from "../components/validated-text-input.jsx";
import Remote from "../data/remote.js";
import RemoteService from "../services/remotes-service.js";
import EventEmitter from "../tools/event-emitter.js";
import ModalHandler from "./modal-handler.js";
import Modal from "./modal.jsx";

const eventEmitter = new EventEmitter();
const REMOTE_EDITED_EVENT = "success";
const MIN_TITLE_LENGTH = 3;
const modalHandler = new ModalHandler();

const [remoteId, setRemoteId] = createSignal(null);

function EditRemoteModal(props) {
  const [title, setTitle] = createSignal("");
  const [commands, setCommands] = createSignal([]);
  const [availableCommands, { refetch: refetchAvailableCommands }] =
    createResource(RemoteService.getCommands);
  const [remote, {}] = createResource(
    remoteId,
    () => RemoteService.getRemote(remoteId()),
    { initialValue: new Remote() }
  );
  const [error, setError] = createSignal("");

  const isTitleValid = createMemo(() => title().length >= MIN_TITLE_LENGTH);
  const isFormValid = createMemo(() => isTitleValid());

  createEffect(() => {
    if (!remote()) return;
    setTitle(remote().getTitle());
    setCommands(remote().getCommands());
  });

  modalHandler.onShow(() => {
    refetchAvailableCommands();
  });

  async function handleEditRemote() {
    try {
      await RemoteService.updateRemote(
        new Remote({
          id: remote().getId(),
          title: title(),
          commands: commands(),
        })
      );
    } catch (e) {
      setError(e.message);
      console.error(e);
      return;
    }
    resetFields();
    EditRemoteModal.Handler.hide();
    eventEmitter.dispatchEvent(REMOTE_EDITED_EVENT);
  }

  function resetFields() {
    setTitle("");
    setCommands([]);
    setRemoteId("");
    setError("");
  }

  function handleCommandSelect(item) {
    setCommands([...commands(), item]);
  }

  function handleCommandDeselect(item) {
    setCommands(
      commands().filter((command) => command.getId() !== item.getId())
    );
  }

  return (
    <Modal
      ref={props.ref}
      id="editRemoteModal"
      modalTitle="New Remote"
      centered={true}
    >
      <div class="modal-body bg-body-tertiary">
        <Show when={error() !== ""}>
          <div class="alert alert-danger" role="alert">
            {error()}
          </div>
        </Show>
        <div class="mb-3 row">
          <label for="edit_remote_title" class="col-form-label col-sm-1">
            Title
          </label>
          <ValidatedTextInput
            class="col-sm-11"
            id="edit_remote_title"
            valid={isTitleValid()}
            value={title()}
            onInput={(e) => setTitle(e.target.value)}
            errorText={`Title must be at least ${MIN_TITLE_LENGTH} characters long`}
          />
        </div>
        <ListManager
          style="height: 20em;"
          items={commands()}
          availableItems={availableCommands()}
          itemToString={(command) =>
            `${command.getTitle()} (${command.getProtocol()}:${command.getCommandType()})`
          }
          onItemSelect={handleCommandSelect}
          onItemDeselect={handleCommandDeselect}
          itemsTitle="Selected Commands"
          availableItemsTitle="Available Commands"
          itemsEqual={(a, b) => a.getId() === b.getId()}
        />
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
          Cancel
        </button>
        <button
          type="button"
          onClick={handleEditRemote}
          class="btn btn-primary"
          disabled={!isFormValid()}
        >
          Edit
        </button>
      </div>
    </Modal>
  );
}

EditRemoteModal.Handler = modalHandler;
EditRemoteModal.onRemoteEdited = (callback) =>
  eventEmitter.on(REMOTE_EDITED_EVENT, callback);
EditRemoteModal.setRemoteId = setRemoteId;

export default EditRemoteModal;
