<script lang="ts">
  import { getStores } from "$app/stores";

  import { sl3 } from "$lib/clients/sl3";
  import Modal from "$lib/components/common/Modal.svelte";
  import ModalBody from "$lib/components/common/ModalBody.svelte";
  import { getModalContext } from "$lib/components/contexts/ModalContext.svelte";
  import { getScopeContext } from "$lib/components/contexts/ScopeContext.svelte";
  import { getSprintListContext } from "$lib/components/contexts/SprintListContext.svelte";
  import PartInput from "$lib/components/controls/PartInput.svelte";
  import SprintKindSelect from "$lib/components/controls/SprintKindSelect.svelte";
    import TagInput from "$lib/components/controls/TagInput.svelte";
  import TimeRangeInput from "$lib/components/controls/TimeRangeInput.svelte";
  import Checkbox from "$lib/components/layout/Checkbox.svelte";
  import type Scope from "$lib/models/scope";
  import type Sprint from "$lib/models/sprint";
  import { SprintKind, type SprintInput, type SprintInputPart } from "$lib/models/sprint";
  import { formatFormTime } from "$lib/utils/date";
  import { partsDiff } from "$lib/utils/sprint";

  const {currentModal, closeModal} = getModalContext();
  const {scope} = getScopeContext();
  const {reloadSprintList} = getSprintListContext();
  const {page} = getStores();

  let sprint: SprintInput
  let sprintId: number
  let scopeId: number
  let oldParts: SprintInputPart[]
  let intervalName: string;
  
  let openedDate: Date
  let op: string
  let error: string
  let loading: boolean
  let show: boolean

  $: switch ($currentModal.name) {
    case "sprint.create":
      initCreate($scope)
      break;
    case "sprint.edit":
      initEdit($currentModal.sprint)
      break;

    default:
      loading = false;
      error = null;
      show = false;
  }

  function initCreate(scope: Scope) {
    sprint = {
      name: "",
      description: "",
      fromTime: "",
      toTime: "",
      kind: SprintKind.Stats,
      aggregateName: "",
      aggregateRequired: 0,
      isCoarse: false,
      isTimed: false,
      isUnweighted: false,
      parts: [],
      tags: [],
    }
    intervalName = "this_month";
    scopeId = scope.id;

    op = "Create"
    openedDate = new Date();
    show = true;
  }

  function initEdit(current: Sprint) {
    sprint = {
      name: current.name,
      description: current.description,
      fromTime: formatFormTime(current.fromTime),
      toTime: formatFormTime(current.toTime),
      kind: current.kind,
      aggregateName: current.aggregateName,
      aggregateRequired: current.aggregateRequired,
      isCoarse: current.isCoarse,
      isTimed: current.isTimed,
      isUnweighted: current.isUnweighted,
      tags: [...(current.tags||[])],
    };
    sprintId = current.id;
    scopeId = current.scopeId;
    intervalName = "specific_dates";

    if (sprint.kind === SprintKind.Stats) {
      sprint.parts = current.progress.map(p => ({partId: p.id, required: p.required})); 
    } else {
      sprint.parts = current.partIds.map(p => ({partId: p, required: 0}));
    }
    oldParts = [...sprint.parts];

    op = "Edit"
    openedDate = new Date();
    show = true;
  }

  async function submit() {
    error = null;
    loading = true;

    const submission: SprintInput = {
      ...sprint,
      fromTime: new Date(sprint.fromTime).toISOString(),
      toTime: new Date(sprint.toTime).toISOString(),
    }

    try {
      switch (op) {
        case "Create":
          await sl3(fetch).createSprint(scopeId, submission);
          break;
        case "Edit":
          await sl3(fetch).updateSprint(scopeId, sprintId, submission);
          const {added, removed} = partsDiff(oldParts, submission.parts)
          for (const part of added) {
            await sl3(fetch).upsertSprintPart(scopeId, sprintId, part).catch(() => {});
          }
          for (const part of removed) {
            await sl3(fetch).deleteSprintPart(scopeId, sprintId, part).catch(() => {});
          }

          break;
      }

      await reloadSprintList();

      closeModal();
    } catch(err) {
      if (err.statusCode != null) {
        error = err.statusMessage;
      } else {
        error = err
      }

    } finally {
      loading = false;
    }
  }
</script>

<form on:submit|preventDefault={submit}>
  <Modal wide closable show={show} verb={op} noun="sprint" disabled={loading} error={error}>
    <ModalBody>
      <label for="name">Name</label>
      <input name="name" type="text" bind:value={sprint.name} />
      <label for="description">Description</label>
      <textarea name="description" bind:value={sprint.description} />
      <label for="time">Time</label>
      <TimeRangeInput openDate={openedDate} bind:from={sprint.fromTime} bind:to={sprint.toTime} bind:intervalName={intervalName} />
      <label for="aggregateName">Aggregate Name</label>
      <input name="aggregateName" type="text" bind:value={sprint.aggregateName} />
      <label for="tags">Tags</label>
      <TagInput exclaimMode bind:value={sprint.tags} />
      {#if sprint.kind != SprintKind.Items}
        <label for="aggregateValue">Aggregate Goal</label>
        <input name="aggregateValue" type="number" bind:value={sprint.aggregateRequired} />
      {/if}
      <Checkbox bind:checked={sprint.isTimed} label="Sprint is timed" />
      <Checkbox bind:checked={sprint.isCoarse} label="Show only aggregate" />
      <Checkbox bind:checked={sprint.isUnweighted} label="Aggregate is unweighted" />
    </ModalBody>
    <ModalBody>
      <label for="kind">Kind</label>
      <SprintKindSelect disabled={op === "Edit"} bind:kind={sprint.kind} />
      <label for="parts">Parts</label>
      <PartInput bind:value={sprint.parts} kind={sprint.kind} scopeId={scopeId} />
    </ModalBody>
  </Modal>
</form>