<!--
This page is quite large, and handles the form in which users can create and
edit transactions. It's accessed through two routes:
- /profiles/:profileName/transactions/:transactionId for editing
- /profiles/:profileName/add-transaction for creating a new transaction

The form consists of a few main sections:
- Standard form controls for various fields like timestamp, amount, description, etc.
- Line items table for editing the list of line items.
- Tags editor for editing the set of tags.
-->
<script setup lang="ts">
import { AccountApiClient, type Account } from '@/api/account'
import { DataApiClient, floatMoneyToInteger, type Currency } from '@/api/data'
import AppPage from '@/components/common/AppPage.vue'
import CategorySelect from '@/components/CategorySelect.vue'
import FileSelector from '@/components/common/FileSelector.vue'
import AppForm from '@/components/common/form/AppForm.vue'
import FormControl from '@/components/common/form/FormControl.vue'
import FormGroup from '@/components/common/form/FormGroup.vue'
import LineItemsEditor from '@/components/LineItemsEditor.vue'
import { computed, onMounted, ref, watch, type Ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import VendorSelect from '@/components/VendorSelect.vue'
import TagsSelect from '@/components/TagsSelect.vue'
import {
  defaultEmptyFormFields,
  DraftEditorContext,
  loadEditorContextFromRoute,
  NewTransactionEditorContext,
  TransactionEditorContext,
  type TransactionEditorAction,
  type TransactionEditorContextBase,
  type TransactionEditorFormFields,
} from './util'
import ButtonBar from '@/components/common/ButtonBar.vue'
import AppButton from '@/components/common/AppButton.vue'
import { showAlert } from '@/util/alert'

const route = useRoute()
const router = useRouter()

const accountApi = new AccountApiClient(route)

// General data used to populate form controls.
const allCurrencies: Ref<Currency[]> = ref([])
const availableCurrencies = computed(() => {
  return allCurrencies.value.filter((c) =>
    allAccounts.value.some((a) => a.currency.code === c.code),
  )
})
const allAccounts: Ref<Account[]> = ref([])
const availableAccounts = computed(() => {
  return allAccounts.value.filter((a) => a.currency.code === formData.value.currency?.code)
})

// Reactive form data:
const loading = ref(false)
const formData: Ref<TransactionEditorFormFields> = ref(defaultEmptyFormFields())
const editorContext: Ref<TransactionEditorContextBase> = ref(new NewTransactionEditorContext())
const pageTitle = computed(() => {
  if (editorContext.value instanceof NewTransactionEditorContext) {
    return 'Add Transaction'
  } else if (editorContext.value instanceof DraftEditorContext) {
    return 'Edit Draft Transaction'
  } else if (editorContext.value instanceof TransactionEditorContext) {
    return 'Edit Transaction'
  }
  return 'Edit Transaction'
})

watch(availableCurrencies, (newValue: Currency[]) => {
  if (newValue.length === 1) {
    formData.value.currency = newValue[0]
  }
})

onMounted(async () => {
  const dataClient = new DataApiClient()

  // Fetch various collections of data needed for different user choices.
  dataClient.getCurrencies().then((currencies) => (allCurrencies.value = currencies))
  accountApi.getAccounts().then((accounts) => (allAccounts.value = accounts))

  try {
    editorContext.value = await loadEditorContextFromRoute(route)
  } catch (err) {
    console.error(err)
  }
  formData.value = editorContext.value.initializeFormFields(route.query)
})

function onActionClicked(action: TransactionEditorAction) {
  loading.value = true
  action
    .callback(formData.value, route, router)
    .catch((err) => {
      showAlert(err)
    })
    .finally(() => {
      loading.value = false
    })
}
</script>
<template>
  <AppPage :title="pageTitle">
    <AppForm>
      <!-- Initial draft-only form group: -->
      <FormGroup v-if="editorContext instanceof DraftEditorContext">
        <FormControl
          label="Template Name"
          hint="Add a name to this draft to turn it into a Template, which you can use when creating new transactions or scheduled transactions."
        >
          <input
            type="text"
            v-model="formData.templateName"
            :disabled="loading"
            style="max-width: 200px"
            maxlength="32"
          />
        </FormControl>
      </FormGroup>

      <FormGroup>
        <!-- Basic properties -->
        <FormControl label="Timestamp">
          <input
            type="datetime-local"
            v-model="formData.timestamp"
            step="1"
            :disabled="loading"
            style="min-width: 250px"
          />
        </FormControl>
        <FormControl label="Amount">
          <input
            type="number"
            v-model="formData.amount"
            step="0.01"
            min="0.01"
            :disabled="loading"
            style="max-width: 100px"
          />
        </FormControl>
        <FormControl label="Currency">
          <select
            v-model="formData.currency"
            :disabled="loading || availableCurrencies.length === 1"
          >
            <option
              v-for="currency in availableCurrencies"
              :key="currency.code"
              :value="currency"
            >
              {{ currency.code }}
            </option>
          </select>
        </FormControl>
        <FormControl
          label="Description"
          style="min-width: 200px"
        >
          <textarea
            v-model="formData.description"
            :disabled="loading"
          ></textarea>
        </FormControl>
      </FormGroup>

      <FormGroup>
        <!-- Vendor & Category -->
        <FormControl label="Vendor">
          <VendorSelect v-model="formData.vendor" />
        </FormControl>
        <FormControl label="Category">
          <CategorySelect v-model="formData.categoryId" />
        </FormControl>
      </FormGroup>

      <FormGroup>
        <!-- Accounts -->
        <FormControl label="Credited Account">
          <select
            v-model="formData.creditedAccountId"
            :disabled="loading"
          >
            <option
              v-for="account in availableAccounts"
              :key="account.id"
              :value="account.id"
            >
              {{ account.name }} ({{ account.numberSuffix }})
            </option>
            <option :value="null">None</option>
          </select>
        </FormControl>
        <FormControl label="Debited Account">
          <select
            v-model="formData.debitedAccountId"
            :disabled="loading"
          >
            <option
              v-for="account in availableAccounts"
              :key="account.id"
              :value="account.id"
            >
              {{ account.name }} ({{ account.numberSuffix }})
            </option>
            <option :value="null">None</option>
          </select>
        </FormControl>
      </FormGroup>

      <LineItemsEditor
        v-if="formData.currency"
        v-model="formData.lineItems"
        :currency="formData.currency"
        :transaction-amount="floatMoneyToInteger(formData.amount ?? 0, formData.currency)"
      />

      <FormGroup>
        <!-- Tags -->
        <FormControl label="Tags">
          <TagsSelect v-model="formData.tags" />
        </FormControl>
      </FormGroup>

      <FormGroup>
        <h5>Attachments</h5>
        <FileSelector
          :initial-files="formData.existingAttachments"
          v-model:uploaded-files="formData.attachmentsToUpload"
          v-model:removed-files="formData.removedAttachmentIds"
        />
      </FormGroup>

      <!-- One last group for less-often used fields: -->
      <FormGroup>
        <FormControl
          label="Internal Transfer"
          hint="Mark this transaction as an internal transfer to ignore it in analytics. Useful for things like credit card payments."
        >
          <input
            type="checkbox"
            v-model="formData.internalTransfer"
            :disabled="loading"
          />
        </FormControl>
      </FormGroup>

      <!-- The set of available actions is defined by the current editor context. -->
      <ButtonBar>
        <AppButton
          v-for="action in editorContext.getActions(formData)"
          :key="action.name"
          :disabled="action.disabled"
          @click="onActionClicked(action)"
        >
          {{ action.name }}
        </AppButton>
      </ButtonBar>
    </AppForm>
  </AppPage>
</template>
