<script>
  import { tick } from "svelte"
  import {
    ModalContent,
    TextArea,
    notifications,
    ActionButton,
  } from "@budibase/bbui"
  import { automationStore, selectedAutomation } from "@/stores/builder"
  import AutomationBlockSetup from "../../SetupPanel/AutomationBlockSetup.svelte"
  import { cloneDeep } from "lodash/fp"
  import { AutomationEventType } from "@budibase/types"

  let failedParse = null
  let trigger = {}
  let schemaProperties = {}

  const rowTriggers = [
    AutomationEventType.ROW_DELETE,
    AutomationEventType.ROW_UPDATE,
    AutomationEventType.ROW_SAVE,
    AutomationEventType.ROW_ACTION,
  ]

  /**
   * Parses the automation test data and ensures it is valid
   * @param {object} testData contains all config for the test
   * @returns {object} valid testData
   * @todo Parse *all* data for each trigger type and relay adequate feedback
   */
  const parseTestData = testData => {
    const autoTrigger = $selectedAutomation.data?.definition?.trigger
    const { tableId } = autoTrigger?.inputs || {}

    // Ensure the tableId matches the trigger table for row trigger automations
    if (
      rowTriggers.includes(autoTrigger?.event) &&
      testData?.row?.tableId !== tableId
    ) {
      return {
        // Reset Core fields
        row: { tableId },
        meta: {},
        id: "",
        revision: "",
      }
    } else {
      // Leave the core data as it is
      return cloneDeep(testData)
    }
  }

  /**
   * Before executing a test run, relay if an automation is in a valid state
   * @param {object} trigger The automation trigger config
   * @returns {boolean} validation status
   * @todo Parse *all* trigger types relay adequate feedback
   */
  const isTriggerValid = trigger => {
    if (rowTriggers.includes(trigger?.event) && !trigger?.inputs?.tableId) {
      return false
    }
    return true
  }

  $: currentTestData = $selectedAutomation.data.testData

  // Can be updated locally to avoid race condition when testing
  $: testData = parseTestData(currentTestData)

  $: {
    // clone the trigger so we're not mutating the reference
    trigger = cloneDeep($selectedAutomation.data.definition.trigger)

    // get the outputs so we can define the fields
    let schema = Object.entries(trigger.schema?.outputs?.properties || {})

    if (trigger?.event === AutomationEventType.APP_TRIGGER) {
      schema = [["fields", { customType: "fields" }]]
    }
    schemaProperties = schema
  }

  // Check the schema to see if required fields have been entered
  $: isError =
    !isTriggerValid(trigger) ||
    !(trigger.schema.outputs.required || []).every(
      required => testData?.[required] || required !== "row"
    )

  async function parseTestJSON(e) {
    let jsonUpdate

    try {
      jsonUpdate = JSON.parse(e.detail)
      failedParse = null
    } catch (e) {
      failedParse = "Invalid JSON"
      return false
    }

    if (rowTriggers.includes(trigger?.event)) {
      const tableId = trigger?.inputs?.tableId

      if (!jsonUpdate.row) {
        jsonUpdate.row = {}
      }

      // Reset the tableId as it must match the trigger
      if (jsonUpdate?.row?.tableId !== tableId) {
        jsonUpdate.row.tableId = tableId
      }
    }

    const updatedAuto =
      automationStore.actions.addTestDataToAutomation(jsonUpdate)
    await automationStore.actions.save(updatedAuto)
  }

  const testAutomation = async () => {
    // Ensure testData reactiveness is processed
    await tick()
    try {
      await automationStore.actions.test($selectedAutomation.data, testData)
      $automationStore.showTestPanel = true
    } catch (error) {
      notifications.error(error)
    }
  }

  const toggle = () => {
    selectedValues = !selectedValues
    selectedJSON = !selectedJSON
  }
  let selectedValues = true
  let selectedJSON = false
</script>

<ModalContent
  title="Add test data"
  confirmText="Run test"
  size="L"
  showConfirmButton={true}
  disabled={isError}
  onConfirm={testAutomation}
  cancelText="Cancel"
>
  <div class="size">
    <div class="options">
      <ActionButton quiet selected={selectedValues} on:click={toggle}
        >Use values</ActionButton
      >
      <ActionButton quiet selected={selectedJSON} on:click={toggle}
        >Use JSON</ActionButton
      >
    </div>
  </div>

  {#if selectedValues}
    <div class="tab-content-padding">
      <AutomationBlockSetup
        {schemaProperties}
        isTestModal
        {testData}
        block={trigger}
        on:update={e => {
          const { testData: updatedTestData } = e.detail
          testData = parseTestData(updatedTestData)
        }}
      />
    </div>
  {/if}
  {#if selectedJSON}
    <div class="text-area-container">
      <TextArea
        value={JSON.stringify($selectedAutomation.data.testData, null, 2)}
        error={failedParse}
        on:change={async e => await parseTestJSON(e)}
      />
    </div>
  {/if}
</ModalContent>

<style>
  .text-area-container :global(textarea) {
    min-height: 300px;
    height: 300px;
  }

  .tab-content-padding {
    padding: 0 var(--spacing-s);
  }

  .options {
    display: flex;
    align-items: center;
    gap: 8px;
  }
</style>