import {
  Meta,
  Preview,
  Props,
  Story,
  SourceState,
} from "@storybook/addon-docs/blocks";
import { useDisclosure } from "../../hooks";
import { JUSTIFY, ORIENTATION } from "../../types";
import { Button, BUTTON_SIZE, BUTTON_VARIANT } from "../Button";
import { Stack } from "../Stack";
import { Flex } from "../Flex";
import { FormGroup } from "../FormGroup";
import { ICON_TYPE } from "../Icon";
import { Input } from "../Input";
import { Label } from "../Label";
import { Modal } from "../Modal";
import { Table } from "../Table";
import { Textarea } from "../Textarea";
import { Markdown } from "../Markdown";
import { MarkdownEditor } from "./MarkdownEditor";

<Meta title="Components/Forms/Markdown Editor" component={MarkdownEditor} />

export const Fragment = (props) => <div {...props} />;

# MarkdownEditor

MarkdownEditor uses [react-codemirror](https://github.com/JedWatson/react-codemirror)
to create a Markdown editor with a live preivew in an overlay.

```jsx
import { MarkdownEditor } from "@aptible/arrow-ds";
```

export const exampleContent = `[Control: Third Party Access Review Control](/)\n## Third Party Access Reviews Procedure\n\n### Review Access Controls\n\n**To be performed at the following times:**\n* Whenever an ISMS Role Membership is added, updated, or deleted\n* Whenever an Access Control Review is due (Every 7 months)\n\n**In accordance with the following requirements:**\n\n**1. Review Access Grants to Information Systems**\n\nThe Security Team shall ensure that a review of access grants to information systems is completed. To perform an access review, either the Security Team or asset owners shall open the Security Management Tasks and review the access grants to ensure that:\n\n* All users of each information system have a business need for access\n* User permissions are set appropriately based on business needs\n* Multi-factor authentication status is appropriate for relevant systems\n\nThe Security Team or asset owners shall log the following information in the Security Management Tasks:\n\n* The date of the review\n* The information systems that were reviewed\n* The individual(s) who performed the review Notes from the review, including any changes to access as a result of the review\n* If the Security Team has delegated the access reviews to asset owners, the Security Team shall ensure that the reviews are completed.\n\n**2. Review privileged utility programs**\n\nThe Security Officer shall review the access levels of utility programs that can override system and application controls ("privileged utility programs") that have access to Sensitive/Regulated Information to ensure that the permissions granted to them continue to be appropriate.`;

<Preview withSource={SourceState.OPEN}>
  <Story name="MarkdownEditor">
    {() => {
      const [value, setValue] = React.useState(exampleContent);
      const { isOpen, onOpen, onClose } = useDisclosure(false);
      const onSave = () => {
        console.log("Save handler called");
        onClose();
      };
      const onCancel = () => {
        console.log("Cancel handler called");
        onClose();
      };
      return (
        <Fragment>
          <Button onClick={onOpen}>Open Markdown editor</Button>
          <MarkdownEditor
            isOpen={isOpen}
            onCancel={onCancel}
            onSave={onSave}
            onClose={onClose}
            value={value}
            onChange={(editor, data, val) => {
              setValue(val);
            }}
          />
        </Fragment>
      );
    }}
  </Story>
</Preview>

## Custom Props

These are the custom props that extend [`BoxProps`](/?path=/docs/components-box--box#all-props).

<Props of={MarkdownEditor} />

## Demos

### Markdown editor without save and cancel buttons

The save and cancel buttons will be hidden if their respective handlers are not
passed.

<Preview>
  <Story name="MarkdownEditor without save and cancel buttons">
    {() => {
      const [value, setValue] = React.useState(exampleContent);
      const { isOpen, onOpen, onClose } = useDisclosure(false);
      return (
        <Fragment>
          <Button onClick={onOpen}>Open Markdown editor</Button>
          <MarkdownEditor
            isOpen={isOpen}
            onClose={onClose}
            value={value}
            onChange={(editor, data, val) => {
              setValue(val);
            }}
          />
        </Fragment>
      );
    }}
  </Story>
</Preview>

### Markdown editor with simulated loading when saved

<Preview>
  <Story name="MarkdownEditor with simulated loading when saved">
    {() => {
      const [value, setValue] = React.useState(exampleContent);
      const [isLoading, setIsLoading] = React.useState(false);
      const { isOpen, onOpen, onClose } = useDisclosure(false);
      const onSave = () => {
        console.log("Save handler called");
        setIsLoading(true);
        setTimeout(() => {
          setIsLoading(false);
          onClose();
        }, 4000);
      };
      const onCancel = () => {
        console.log("Cancel handler called");
        onClose();
      };
      return (
        <Fragment>
          <Button onClick={onOpen}>Open Markdown editor</Button>
          <MarkdownEditor
            isOpen={isOpen}
            onCancel={onCancel}
            onSave={onSave}
            onClose={onClose}
            value={value}
            onChange={(editor, data, val) => {
              setValue(val);
            }}
            isLoading={isLoading}
          />
        </Fragment>
      );
    }}
  </Story>
</Preview>

### Markdown editor within a modal

The save and cancel buttons will be hidden if their respective handlers are not
passed.

<Preview>
  <Story name="MarkdownEditor in modal">
    {() => {
      const [value, setValue] = React.useState(exampleContent);
      const {
        isOpen: isModalOpen,
        onOpen: openModal,
        onClose: closeModal,
      } = useDisclosure();
      const {
        isOpen: isEditorOpen,
        onOpen: openEditor,
        onClose: closeEditor,
      } = useDisclosure();
      const onSubmit = (event) => {
        event.preventDefault();
      };
      return (
        <Fragment>
          <Button onClick={openModal}>Show Modal</Button>
          <Modal
            title="Markdown editor"
            isOpen={isModalOpen}
            onClose={closeModal}
          >
            <form onSubmit={onSubmit}>
              <Modal.Body>
                <FormGroup>
                  <Label htmlFor="name">Name</Label>
                  <Input name="name" id="name" type="text" autoFocus />
                </FormGroup>
                <FormGroup>
                  <Label htmlFor="content">Content</Label>
                  <Flex className="bg-white">
                    <Textarea
                      name="content"
                      id="content"
                      rows={10}
                      value={value}
                      onChange={(event) => setValue(event.target.value)}
                      className="font-mono rounded-r-none"
                    />
                    <Stack
                      className="p-3 rounded-r border-l-0 border-2 border-gray-500"
                      orientation={ORIENTATION.VERTICAL}
                      justify={JUSTIFY.END}
                    >
                      <Button
                        variant={BUTTON_VARIANT.UTILITY}
                        icon={ICON_TYPE.EXPAND}
                        onClick={openEditor}
                        aria-label="Expand editor"
                      />
                    </Stack>
                  </Flex>
                  <MarkdownEditor
                    isOpen={isEditorOpen}
                    onChange={(editor, data, val) => {
                      setValue(val);
                    }}
                    onClose={closeEditor}
                    value={value}
                    showBackdrop={false}
                  />
                </FormGroup>
              </Modal.Body>
              <Modal.Footer>
                <Stack reverse>
                  <Button type="submit" size={BUTTON_SIZE.LARGE}>
                    Submit
                  </Button>
                  <Button
                    size={BUTTON_SIZE.LARGE}
                    variant={BUTTON_VARIANT.SECONDARY}
                    onClick={closeModal}
                  >
                    Cancel
                  </Button>
                </Stack>
              </Modal.Footer>
            </form>
          </Modal>
        </Fragment>
      );
    }}
  </Story>
</Preview>

### Markdown editor within a table

The save and cancel buttons should behave the same way in both the table cell
and the Markdown editor.

<Preview>
  <Story name="MarkdownEditor in table">
    {() => {
      const [value, setValue] = React.useState(exampleContent);
      const [isEditing, setIsEditing] = React.useState(true);
      const {
        isOpen: isEditorOpen,
        onOpen: openEditor,
        onClose: closeEditor,
      } = useDisclosure();
      const onSave = () => {
        console.log("Save handler called");
        setIsEditing(false);
      };
      const onCancel = () => {
        console.log("Cancel handler called");
        setIsEditing(false);
      };
      return (
        <Fragment>
          <Table>
            <Table.Head>
              <Table.Row>
                <Table.HeaderCell sortable={false}>Property</Table.HeaderCell>
                <Table.HeaderCell sortable={false}>Value</Table.HeaderCell>
              </Table.Row>
            </Table.Head>
            <Table.Body>
              <Table.Row>
                <Table.Cell className="font-medium">Name</Table.Cell>
                <Table.Cell>Control name</Table.Cell>
              </Table.Row>
              <Table.Row>
                <Table.Cell className="font-medium">Content</Table.Cell>
                <Table.Cell removePadding={isEditing}>
                  {isEditing ? (
                    <Flex className="bg-white">
                      <Textarea
                        name="content"
                        id="content"
                        rows={10}
                        value={value}
                        onChange={(event) => setValue(event.target.value)}
                        className="font-mono rounded-r-none"
                      />
                      <Stack
                        className="p-3 rounded-r border-l-0 border-2 border-gray-500"
                        orientation={ORIENTATION.VERTICAL}
                        justify={JUSTIFY.BETWEEN}
                      >
                        <Stack orientation={ORIENTATION.VERTICAL}>
                          <Button
                            variant={BUTTON_VARIANT.UTILITY}
                            icon={ICON_TYPE.CHECK}
                            onClick={onSave}
                            aria-label="Save edits"
                          />
                          <Button
                            variant={BUTTON_VARIANT.UTILITY}
                            icon={ICON_TYPE.TIMES}
                            onClick={onCancel}
                            aria-label="Cancel edits"
                          />
                        </Stack>
                        <Button
                          variant={BUTTON_VARIANT.UTILITY}
                          icon={ICON_TYPE.EXPAND}
                          onClick={openEditor}
                          aria-label="Expand editor"
                        />
                      </Stack>
                    </Flex>
                  ) : (
                    <Flex className="relative">
                      <Markdown>{value}</Markdown>
                      <Button
                        icon={ICON_TYPE.PEN}
                        variant={BUTTON_VARIANT.MINIMAL}
                        onClick={() => setIsEditing(true)}
                        className="absolute top-0 right-0 text-iconSm text-gray-400 hover:text-gray-600"
                      />
                    </Flex>
                  )}
                  <MarkdownEditor
                    isOpen={isEditorOpen}
                    onChange={(editor, data, val) => {
                      setValue(val);
                    }}
                    onSave={() => {
                      onSave();
                      closeEditor();
                    }}
                    onCancel={() => {
                      onCancel();
                      closeEditor();
                    }}
                    onClose={closeEditor}
                    value={value}
                  />
                </Table.Cell>
              </Table.Row>
            </Table.Body>
          </Table>
        </Fragment>
      );
    }}
  </Story>
</Preview>
