<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 { getItemListContext } from "$lib/components/contexts/ItemListContext.svelte";
  import { getItemMultiListContext } from "$lib/components/contexts/ItemMultiListContext.svelte";
  import { getModalContext } from "$lib/components/contexts/ModalContext.svelte";
  import { getProjectContext } from "$lib/components/contexts/ProjectContext.svelte";
  import { getScopeContext } from "$lib/components/contexts/ScopeContext.svelte";
  import { getScopeListContext } from "$lib/components/contexts/ScopeListContext.svelte";
  import { getSprintListContext } from "$lib/components/contexts/SprintListContext.svelte";
  import AcquiredTimeInput from "$lib/components/controls/AcquiredTimeInput.svelte";
  import RequirementSelect from "$lib/components/controls/RequirementSelect.svelte";
  import StatInput from "$lib/components/controls/StatInput.svelte";
  import type Item from "$lib/models/item";
  import type { ItemInput } from "$lib/models/item";
  import type { Requirement } from "$lib/models/project";
  import type Scope from "$lib/models/scope";
  import { formatFormTime } from "$lib/utils/date";
  import { statDiff } from "$lib/utils/stat";

  const {currentModal, closeModal} = getModalContext();
  const {scope} = getScopeContext();
  const {scopes} = getScopeListContext();
  const {project, reloadProject} = getProjectContext();
  const {reloadItemList} = getItemListContext();
  const {reloadSprintList} = getSprintListContext();
  const {reloadItemLists} = getItemMultiListContext();
  const {page} = getStores();

  let item: ItemInput
  let itemId: number
  let scopeId: number
  let currentStats: ItemInput["stats"]
  let openedDate: Date
  let requirementName: string
  let op: string
  let initOnList: number[] = [];

  let error: string
  let loading: boolean
  let show: boolean

  $: switch ($currentModal.name) {
    case "item.create":
      initCreate($scope, $currentModal.requirement)
      break;
    case "item.edit": {
      const reqId = $currentModal.item.requirementId;
      initEdit($currentModal.item, $project.requirements.find(r => r.id === reqId), $scope)
      break;
    }

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

  function initCreate(scope: Scope, requirement?: Requirement) {
    let stats = requirement?.stats.map(s => ({statId: s.id, required: 0, acquired: 0}));
    if (stats == null) {
      stats = scope.stats.map(s => ({statId: s.id, required: 0, acquired: 0}))
    } else {
      initOnList = requirement.stats.filter(s => s.required > 0).map(s => s.id);
    }

    item = {
      name: "",
      description: "",
      requirementId: requirement?.id,
      stats: stats,
      acquiredTime: null,
      scheduledDate: null,
    }

    op = "Create"
    scopeId = scope.id;
    openedDate = new Date();
    requirementName = requirement?.name;
    show = true;
  }

  function initEdit(current: Item, requirement?: Requirement, scope?: Scope) {
    const req = $project.requirements?.find(r => r.id === current.requirementId);
    let ctxStats = requirement?.stats.map(s => ({statId: s.id, required: 0, acquired: 0}));
    if (ctxStats == null || ctxStats.length === 0) {
      let actualScope = scope;
      if (actualScope.id !== current.scopeId && $scopes?.length > 0) {
        actualScope = $scopes.find(s => s.id === current.scopeId)
      }

      ctxStats = actualScope.stats.map(s => ({statId: s.id, required: 0, acquired: 0}));
    }
    const inputStats = current.stats.map(s => ({statId: s.id, acquired: s.acquired, required: s.required}));

    item = {
      name: current.name,
      description: current.description,
      requirementId: current.requirementId,
      stats: ctxStats.map(s => inputStats.find(s2 => s2.statId === s.statId) || s),
      acquiredTime: formatFormTime(current.acquiredTime),
      scheduledDate: current.scheduledDate,
    };
    itemId = current.id;
    scopeId = current.scopeId;
    currentStats = [...item.stats];

    op = "Edit"
    openedDate = new Date();
    requirementName = current.requirement?.name;
    show = true;
  }

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

    const submission: ItemInput = {
      ...item,
      acquiredTime: item.acquiredTime ? new Date(item.acquiredTime).toISOString() : void(0),
      stats: item.stats.filter(s => s.required > 0),
    }

    try {
      switch (op) {
        case "Create":
          if (!!submission.acquiredTime) {
            for (const stat of submission.stats) {
              stat.acquired = stat.required
            }
          } else {
            for (const stat of submission.stats) {
              stat.acquired = 0
            }
          }

          await sl3(fetch, $page.stuff.idToken).createItem(scopeId, submission);
          break;
        case "Edit":
          if (!submission.acquiredTime) {
            for (const stat of submission.stats) {
              stat.acquired = 0
            }
            submission.clearAcquiredTime = true;
          }

          submission.stats = statDiff(currentStats, submission.stats)
          await sl3(fetch, $page.stuff.idToken).updateItem(scopeId, itemId, submission);
          break;
      }
    
      // Wait for project reload if it's updating a project
      if (item.requirementId != null) {
        await reloadProject();
      }

      await reloadItemList();
      await reloadSprintList(); 
      reloadItemLists();

      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="Item" disabled={loading} error={error}>
    <ModalBody>
      <label for="name">Name</label>
      <input name="name" type="text" bind:value={item.name} />
      <label for="acquiredTime">Acquired</label>
      <AcquiredTimeInput openDate={openedDate} bind:value={item.acquiredTime} />
      <label for="description">Description</label>
      <textarea name="description" bind:value={item.description} />
    </ModalBody>
    <ModalBody>
      {#if requirementName != null}
        <label for="req">Project Requirement</label>
        {#if $project.id != null}
          <RequirementSelect disabled={op === "Create"} requirements={$project.requirements} bind:value={item.requirementId} />
        {:else}
          <input disabled name="req" type="text" value={requirementName} />
        {/if}
      {/if}
      <label for="stats">Stats</label>
      <StatInput 
        zeroDeletes showRequired 
        overrideScopeId={scopeId}
        initOnList={initOnList}
        showAcquired={op === "Edit" && !!item.acquiredTime} 
        hideUnseen={!!item.requirementId} 
        bind:value={item.stats} 
      />
    </ModalBody>
  </Modal>
</form>