<template>
  <section class="content-grid">
    <!-- General ledger (computed depreciation rollup) -->
    <v-card class="span-12 panel-pad">
      <div class="toolbar-row mb-3">
        <h2 class="section-title">General ledger</h2>
        <v-spacer />
        <v-select v-model="ledgerBook" :items="bookCodeItems" label="Book" density="compact" hide-details style="max-width:180px" @update:model-value="loadLedger" />
        <v-text-field v-model.number="ledgerYear" type="number" label="Year" density="compact" hide-details style="max-width:120px" @update:model-value="loadLedger" />
        <v-menu>
          <template #activator="{ props }">
            <v-btn v-bind="props" color="secondary" size="small" prepend-icon="mdi-download">Export</v-btn>
          </template>
          <v-list density="compact">
            <v-list-item v-for="format in ['pdf', 'xlsx', 'csv']" :key="format" :title="format.toUpperCase()" @click="exportLedger(format)" />
          </v-list>
        </v-menu>
      </div>

      <div v-if="ledger">
        <div v-if="ledger.kind === 'maintenance'" class="ledger-summary mb-4">
          <div class="ledger-chip"><span class="quiet">Assets serviced</span><strong>{{ ledger.summary.assets }}</strong></div>
          <div class="ledger-chip"><span class="quiet">Services ({{ ledger.year }})</span><strong>{{ ledger.summary.completions }}</strong></div>
          <div class="ledger-chip"><span class="quiet">Total PM spend</span><strong>{{ currency(ledger.summary.cost) }}</strong></div>
        </div>
        <div v-else class="ledger-summary mb-4">
          <div class="ledger-chip"><span class="quiet">Assets</span><strong>{{ ledger.summary.assets }}</strong></div>
          <div class="ledger-chip"><span class="quiet">Cost</span><strong>{{ currency(ledger.summary.cost) }}</strong></div>
          <div class="ledger-chip"><span class="quiet">Accumulated depr.</span><strong>{{ currency(ledger.summary.accumulated) }}</strong></div>
          <div class="ledger-chip"><span class="quiet">Net book value</span><strong>{{ currency(ledger.summary.nbv) }}</strong></div>
          <div class="ledger-chip"><span class="quiet">{{ ledger.year }} depreciation</span><strong>{{ currency(ledger.summary.depreciation) }}</strong></div>
          <div class="ledger-chip"><span class="quiet">Rule set</span><strong>{{ ledger.rule_set.name || 'Active set' }}</strong></div>
        </div>

        <div style="overflow-x:auto">
          <table class="asset-table">
            <thead>
              <tr><th>GL account</th><th>Account type</th><th class="text-right">Debit</th><th class="text-right">Credit</th></tr>
            </thead>
            <tbody>
              <tr v-for="(line, index) in ledger.accounts" :key="index">
                <td class="font-weight-bold">{{ line.account }}</td>
                <td>{{ line.type }}</td>
                <td class="text-right">{{ line.debit ? currency(line.debit) : '' }}</td>
                <td class="text-right">{{ line.credit ? currency(line.credit) : '' }}</td>
              </tr>
              <tr v-if="!ledger.accounts.length"><td colspan="4" class="quiet">No postings for this book and year.</td></tr>
            </tbody>
            <tfoot>
              <tr>
                <td class="font-weight-bold" colspan="2">Totals</td>
                <td class="text-right font-weight-bold">{{ currency(ledger.accountTotals.debit) }}</td>
                <td class="text-right font-weight-bold">{{ currency(ledger.accountTotals.credit) }}</td>
              </tr>
            </tfoot>
          </table>
        </div>

        <v-expansion-panels class="mt-4" variant="accordion">
          <v-expansion-panel title="Asset detail">
            <v-expansion-panel-text>
              <DataTable
                :columns="detailColumns"
                :rows="ledger.assets"
                row-key="asset_id"
                searchable
                search-placeholder="Filter assets"
                empty-text="No assets in this book."
              >
                <template #cell-asset_id="{ row }">
                  <span class="font-weight-bold">{{ row.asset_id }}</span>
                </template>
              </DataTable>
            </v-expansion-panel-text>
          </v-expansion-panel>
        </v-expansion-panels>
      </div>
      <div v-else class="quiet text-body-2">Select a book to view its general ledger.</div>
      <v-alert v-if="error" type="error" density="compact" class="mt-3">{{ error }}</v-alert>
    </v-card>

    <!-- Chart of accounts + posting defaults (fully audited) -->
    <v-card class="span-12 panel-pad">
      <div class="toolbar-row mb-2">
        <div>
          <h2 class="section-title">Chart of accounts</h2>
          <div class="quiet text-body-2">
            The company's GL accounts. The <strong>posting defaults</strong> below are the fallback accounts the
            depreciation &amp; maintenance ledgers post to when an asset has none of its own. Every change is recorded in
            Admin → Activity &amp; Audit Trail.
          </div>
        </div>
        <v-spacer />
        <v-btn size="small" color="primary" prepend-icon="mdi-plus" @click="openAccount()">Add account</v-btn>
      </div>

      <DataTable
        :columns="accountColumns"
        :rows="accounts"
        row-key="id"
        :page-size="10"
        has-actions
        searchable
        search-placeholder="Filter accounts"
        empty-text="No GL accounts yet."
      >
        <template #cell-type="{ row }">{{ typeLabel(row.type) }}</template>
        <template #cell-active="{ row }"><v-chip size="x-small" :color="row.active ? 'success' : 'error'" variant="tonal">{{ row.active ? 'active' : 'inactive' }}</v-chip></template>
        <template #actions="{ row }">
          <v-btn icon="mdi-pencil" size="small" variant="text" @click="openAccount(row)" />
          <v-btn icon="mdi-delete-outline" size="small" variant="text" color="error" @click="removeAccount(row)" />
        </template>
      </DataTable>

      <v-divider class="my-4" />
      <div class="toolbar-row mb-2">
        <h3 class="section-title">Posting defaults</h3>
        <v-spacer />
        <v-btn size="small" color="primary" variant="tonal" prepend-icon="mdi-content-save" :loading="savingDefaults" @click="saveDefaults">Save defaults</v-btn>
      </div>
      <div class="form-grid">
        <v-select v-model="defaults.asset_account" :items="accountSelectItems" item-title="title" item-value="value" label="Asset cost account" density="compact" clearable />
        <v-select v-model="defaults.accumulated_account" :items="accountSelectItems" item-title="title" item-value="value" label="Accumulated depreciation account" density="compact" clearable />
        <v-select v-model="defaults.expense_account" :items="accountSelectItems" item-title="title" item-value="value" label="Depreciation expense account" density="compact" clearable />
        <v-select v-model="defaults.pm_expense_account" :items="accountSelectItems" item-title="title" item-value="value" label="Maintenance expense account" density="compact" clearable />
        <v-select v-model="defaults.pm_clearing_account" :items="accountSelectItems" item-title="title" item-value="value" label="Maintenance clearing account" density="compact" clearable />
      </div>
      <v-alert v-if="accountError" type="error" density="compact" class="mt-2">{{ accountError }}</v-alert>
      <v-alert v-if="accountMessage" type="success" density="compact" class="mt-2">{{ accountMessage }}</v-alert>
    </v-card>

    <!-- GL journal entries (stored, editable, fully audited) -->
    <v-card class="span-12 panel-pad">
      <div class="toolbar-row mb-3">
        <div>
          <h2 class="section-title">Journal entries</h2>
          <div class="quiet text-body-2">
            Manual &amp; imported GL postings for <strong>{{ ledgerBook }}</strong> ({{ ledgerYear }}). All changes are
            recorded in Admin → Activity &amp; Audit Trail.
          </div>
        </div>
        <v-spacer />
        <v-btn size="small" variant="tonal" prepend-icon="mdi-upload" @click="$refs.glFile.click()">Import</v-btn>
        <input ref="glFile" hidden type="file" accept=".csv,.xlsx,.xls" @change="onImportFile" />
        <v-menu>
          <template #activator="{ props }">
            <v-btn v-bind="props" size="small" variant="tonal" prepend-icon="mdi-download">Export</v-btn>
          </template>
          <v-list density="compact">
            <v-list-item title="CSV" @click="exportEntries('csv')" />
            <v-list-item title="Excel (XLSX)" @click="exportEntries('xlsx')" />
          </v-list>
        </v-menu>
        <v-btn size="small" color="primary" prepend-icon="mdi-plus" @click="openEntry()">Add entry</v-btn>
      </div>

      <div class="ledger-summary mb-3">
        <div class="ledger-chip"><span class="quiet">Entries</span><strong>{{ entrySummary.count }}</strong></div>
        <div class="ledger-chip"><span class="quiet">Debit</span><strong>{{ currency(entrySummary.debit) }}</strong></div>
        <div class="ledger-chip"><span class="quiet">Credit</span><strong>{{ currency(entrySummary.credit) }}</strong></div>
        <div class="ledger-chip"><span class="quiet">Balance</span><strong>{{ currency(entrySummary.balance) }}</strong></div>
      </div>

      <DataTable
        :columns="entryColumns"
        :rows="entries"
        row-key="id"
        :page-size="15"
        has-actions
        searchable
        search-placeholder="Filter entries"
        empty-text="No journal entries for this book and year."
      >
        <template #cell-debit="{ row }">{{ row.debit ? currency(row.debit) : '' }}</template>
        <template #cell-credit="{ row }">{{ row.credit ? currency(row.credit) : '' }}</template>
        <template #cell-source="{ row }"><v-chip size="x-small" variant="tonal">{{ row.source }}</v-chip></template>
        <template #actions="{ row }">
          <v-btn icon="mdi-history" size="small" variant="text" title="Change history" @click="openHistory(row)" />
          <v-btn icon="mdi-pencil" size="small" variant="text" @click="openEntry(row)" />
          <v-btn icon="mdi-delete-outline" size="small" variant="text" color="error" @click="removeEntry(row)" />
        </template>
      </DataTable>
      <v-alert v-if="entryError" type="error" density="compact" class="mt-2">{{ entryError }}</v-alert>
      <v-alert v-if="message" type="success" density="compact" class="mt-2">{{ message }}</v-alert>
    </v-card>

    <!-- Add / edit GL entry -->
    <v-dialog v-model="entryDialog" max-width="640">
      <v-card>
        <v-card-title>{{ entryForm.id ? 'Edit GL entry' : 'New GL entry' }}</v-card-title>
        <v-card-text>
          <div class="form-grid">
            <v-text-field v-model="entryForm.entry_date" type="date" label="Date *" />
            <v-combobox v-model="entryForm.account" :items="accountCodes" label="GL account *" hint="Pick from the chart of accounts or type a code" />

            <v-text-field v-model="entryForm.account_type" label="Account type" />
            <v-text-field v-model="entryForm.reference" label="Reference" />
            <v-text-field v-model.number="entryForm.debit" type="number" prefix="$" label="Debit" />
            <v-text-field v-model.number="entryForm.credit" type="number" prefix="$" label="Credit" />
            <v-text-field v-model="entryForm.external_id" class="full" label="External ID (used to match on re-import)" />
            <v-textarea v-model="entryForm.description" class="full" label="Description" rows="2" />
          </div>
          <v-alert v-if="entryDialogError" type="error" density="compact" class="mt-2">{{ entryDialogError }}</v-alert>
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="entryDialog = false">Cancel</v-btn>
          <v-btn color="primary" prepend-icon="mdi-content-save" :loading="savingEntry" @click="saveEntry">Save entry</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <!-- Import preview / conflict resolution -->
    <v-dialog v-model="importDialog" max-width="760" scrollable>
      <v-card v-if="importPreview">
        <v-card-title>Import preview — {{ ledgerBook }}</v-card-title>
        <v-card-text>
          <div class="ledger-summary mb-3">
            <div class="ledger-chip"><span class="quiet">New</span><strong>{{ importPreview.summary.new }}</strong></div>
            <div class="ledger-chip"><span class="quiet">Update</span><strong>{{ importPreview.summary.update }}</strong></div>
            <div class="ledger-chip"><span class="quiet">Duplicate</span><strong>{{ importPreview.summary.duplicate }}</strong></div>
            <div class="ledger-chip"><span class="quiet">Errors</span><strong>{{ importPreview.summary.error }}</strong></div>
          </div>
          <div class="text-body-2 quiet mb-1">Conflict strategy</div>
          <v-radio-group v-model="importStrategy" inline hide-details density="compact" class="mb-2">
            <v-radio label="Skip conflicts" value="skip" />
            <v-radio label="Merge (update existing)" value="merge" />
            <v-radio label="Insert as new" value="insert" />
          </v-radio-group>
          <div style="overflow-x:auto; max-height:340px">
            <table class="asset-table">
              <thead><tr><th>Status</th><th>Date</th><th>Account</th><th class="text-right">Debit</th><th class="text-right">Credit</th><th>Reference</th></tr></thead>
              <tbody>
                <tr v-for="r in importPreview.rows" :key="r.index">
                  <td><v-chip size="x-small" :color="statusColor(r.status)" variant="tonal">{{ r.status }}</v-chip><span v-if="r.error" class="quiet text-caption"> · {{ r.error }}</span></td>
                  <td>{{ r.entry.entry_date }}</td>
                  <td>{{ r.entry.account }}</td>
                  <td class="text-right">{{ r.entry.debit ? currency(r.entry.debit) : '' }}</td>
                  <td class="text-right">{{ r.entry.credit ? currency(r.entry.credit) : '' }}</td>
                  <td>{{ r.entry.reference }}</td>
                </tr>
              </tbody>
            </table>
          </div>
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="importDialog = false">Cancel</v-btn>
          <v-btn color="primary" prepend-icon="mdi-database-import" :loading="importing" @click="commitImport">Import</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <!-- Per-entry change history (from the audit log) -->
    <v-dialog v-model="historyDialog" max-width="640" scrollable>
      <v-card>
        <v-card-title>Change history</v-card-title>
        <v-card-text>
          <div v-if="historyLoading" class="quiet text-body-2">Loading…</div>
          <div v-else-if="!historyRows.length" class="quiet text-body-2">No recorded changes.</div>
          <div v-for="ev in historyRows" :key="ev.id" class="gl-history-item">
            <div class="toolbar-row mb-1" style="gap:8px">
              <v-chip size="x-small" :color="historyColor(ev.action)" variant="tonal">{{ historyLabel(ev.action) }}</v-chip>
              <span class="text-body-2 font-weight-medium">{{ ev.actor_name || 'System' }}</span>
              <v-spacer />
              <span class="quiet text-caption">{{ shortDate(ev.created_at) }}</span>
            </div>
            <table v-if="changedFields(ev.before, ev.after).length" class="gl-diff">
              <tr v-for="(c, i) in changedFields(ev.before, ev.after)" :key="i">
                <td class="quiet">{{ c.label }}</td>
                <td class="gl-from">{{ c.from }}</td>
                <td class="px-2">→</td>
                <td class="gl-to">{{ c.to }}</td>
              </tr>
            </table>
            <div v-else class="quiet text-caption">No field changes.</div>
          </div>
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="historyDialog = false">Close</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <!-- Add / edit GL account -->
    <v-dialog v-model="accountDialog" max-width="560">
      <v-card>
        <v-card-title>{{ accountForm.id ? 'Edit GL account' : 'New GL account' }}</v-card-title>
        <v-card-text>
          <div class="form-grid">
            <v-text-field v-model="accountForm.code" label="Account code *" />
            <v-text-field v-model="accountForm.name" label="Account name *" />
            <v-select v-model="accountForm.type" :items="accountTypeItems" item-title="title" item-value="value" label="Type" />
            <v-select v-model="accountForm.normal_balance" :items="balanceItems" item-title="title" item-value="value" label="Normal balance" />
            <v-textarea v-model="accountForm.description" class="full" label="Description" rows="2" />
            <v-switch v-model="accountForm.active" label="Active" color="primary" density="compact" hide-details />
          </div>
          <v-alert v-if="accountDialogError" type="error" density="compact" class="mt-2">{{ accountDialogError }}</v-alert>
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="accountDialog = false">Cancel</v-btn>
          <v-btn color="primary" prepend-icon="mdi-content-save" :disabled="!accountForm.code || !accountForm.name" :loading="savingAccount" @click="saveAccount">Save account</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </section>
</template>

<script>
import DataTable from '../components/DataTable.vue';
import { apiRequest, saveBlob } from '../services/api';
import { currency, shortDate } from '../utils/format';

// GL and Journals (Financial → GL and Journals). Combines the computed depreciation GL rollup with the
// stored, editable journal-entries layer (CRUD, CSV/Excel import with conflict-merge preview, export,
// and per-entry change history) for the selected book + year. Loads its own book list to populate the
// book picker. Previously these two panels lived on the Books screen.
export default {
  components: { DataTable },
  props: {
    token: { type: String, required: true }
  },
  data() {
    return {
      books: [],
      ledger: null,
      ledgerBook: 'GAAP',
      ledgerYear: new Date().getFullYear(),
      error: '',
      message: '',
      entries: [],
      entrySummary: { count: 0, debit: 0, credit: 0, balance: 0 },
      entryDialog: false,
      entryForm: this.blankEntry(),
      entryDialogError: '',
      savingEntry: false,
      entryError: '',
      importDialog: false,
      importPreview: null,
      importStrategy: 'merge',
      importing: false,
      historyDialog: false,
      historyRows: [],
      historyLoading: false,
      glFieldLabels: { entry_date: 'Date', account: 'Account', account_type: 'Type', description: 'Description', reference: 'Reference', debit: 'Debit', credit: 'Credit', external_id: 'External ID', asset_id: 'Asset' },
      accounts: [],
      defaults: { asset_account: '', accumulated_account: '', expense_account: '', pm_expense_account: '', pm_clearing_account: '' },
      accountDialog: false,
      accountForm: this.blankAccount(),
      accountDialogError: '',
      savingAccount: false,
      savingDefaults: false,
      accountError: '',
      accountMessage: '',
      accountTypeItems: [
        { title: 'Asset', value: 'asset' },
        { title: 'Contra-asset', value: 'contra_asset' },
        { title: 'Liability', value: 'liability' },
        { title: 'Equity', value: 'equity' },
        { title: 'Revenue', value: 'revenue' },
        { title: 'Expense', value: 'expense' }
      ],
      balanceItems: [{ title: 'Debit', value: 'debit' }, { title: 'Credit', value: 'credit' }]
    };
  },
  computed: {
    bookCodeItems() {
      return this.books.map((book) => book.code);
    },
    detailColumns() {
      const year = this.ledger?.year || this.ledgerYear;
      if (this.ledger?.kind === 'maintenance') {
        return [
          { key: 'asset_id', label: 'Asset ID' },
          { key: 'description', label: 'Description' },
          { key: 'completions', label: 'Services', format: 'number' },
          { key: 'last_service', label: 'Last service', format: 'date' },
          { key: 'cost', label: `${year} PM cost`, format: 'currency' }
        ];
      }
      return [
        { key: 'asset_id', label: 'Asset ID' },
        { key: 'description', label: 'Description' },
        { key: 'asset_account', label: 'Asset acct' },
        { key: 'expense_account', label: 'Expense acct' },
        { key: 'cost', label: 'Cost', format: 'currency' },
        { key: 'depreciation', label: `${year} depr.`, format: 'currency' },
        { key: 'accumulated', label: 'Accum.', format: 'currency' },
        { key: 'nbv', label: 'NBV', format: 'currency' }
      ];
    },
    entryColumns() {
      return [
        { key: 'entry_date', label: 'Date', format: 'date' },
        { key: 'account', label: 'Account' },
        { key: 'account_type', label: 'Type' },
        { key: 'description', label: 'Description' },
        { key: 'reference', label: 'Reference' },
        { key: 'debit', label: 'Debit', format: 'currency' },
        { key: 'credit', label: 'Credit', format: 'currency' },
        { key: 'source', label: 'Source', sortable: false }
      ];
    },
    accountColumns() {
      return [
        { key: 'code', label: 'Code' },
        { key: 'name', label: 'Name' },
        { key: 'type', label: 'Type' },
        { key: 'normal_balance', label: 'Normal balance' },
        { key: 'description', label: 'Description' },
        { key: 'active', label: 'Status', sortable: false }
      ];
    },
    accountSelectItems() {
      return this.accounts.map((account) => ({ title: `${account.code} — ${account.name}`, value: account.code }));
    },
    accountCodes() {
      return this.accounts.map((account) => account.code);
    }
  },
  mounted() {
    this.loadBooks();
    this.loadAccounts();
  },
  methods: {
    currency,
    shortDate,
    async api(path, options = {}) {
      return apiRequest(path, this.token, options);
    },
    // Load the company's books to populate the book picker, then show the selected book's ledger/entries.
    async loadBooks() {
      try {
        const data = await (await this.api('/api/books')).json();
        this.books = data.books;
        if (this.books.length) {
          if (!this.books.some((book) => book.code === this.ledgerBook)) this.ledgerBook = this.books[0].code;
          this.loadLedger();
        }
      } catch (error) {
        this.error = error.message;
      }
    },
    async loadLedger() {
      if (!this.ledgerBook) return;
      this.error = '';
      try {
        const data = await (await this.api(`/api/books/${this.ledgerBook}/ledger?year=${this.ledgerYear}`)).json();
        this.ledger = data.ledger;
      } catch (error) {
        this.error = error.message;
      }
      this.loadEntries();
    },
    async exportLedger(format) {
      const blob = await (await this.api(`/api/books/${this.ledgerBook}/ledger/export`, {
        method: 'POST',
        body: JSON.stringify({ year: this.ledgerYear, format })
      })).blob();
      saveBlob(blob, `deprecore-${this.ledgerBook}-ledger-${this.ledgerYear}.${format}`);
    },
    // ---- GL journal entries -------------------------------------------------
    blankEntry() {
      return { id: null, entry_date: new Date().toISOString().slice(0, 10), account: '', account_type: '', description: '', reference: '', debit: 0, credit: 0, external_id: '' };
    },
    async loadEntries() {
      if (!this.ledgerBook) return;
      this.entryError = '';
      try {
        const data = await (await this.api(`/api/books/${this.ledgerBook}/gl-entries?year=${this.ledgerYear}`)).json();
        this.entries = data.entries;
        this.entrySummary = data.summary;
      } catch (error) {
        this.entryError = error.message;
      }
    },
    openEntry(row) {
      this.entryForm = row ? { ...this.blankEntry(), ...row } : this.blankEntry();
      this.entryDialogError = '';
      this.entryDialog = true;
    },
    async saveEntry() {
      this.savingEntry = true;
      this.entryDialogError = '';
      this.message = '';
      try {
        const method = this.entryForm.id ? 'PUT' : 'POST';
        const url = this.entryForm.id
          ? `/api/books/${this.ledgerBook}/gl-entries/${this.entryForm.id}`
          : `/api/books/${this.ledgerBook}/gl-entries`;
        await this.api(url, { method, body: JSON.stringify(this.entryForm) });
        this.entryDialog = false;
        await this.loadEntries();
      } catch (error) {
        this.entryDialogError = error.message;
      } finally {
        this.savingEntry = false;
      }
    },
    async removeEntry(row) {
      if (!window.confirm('Delete this GL entry? The change is recorded in the audit trail.')) return;
      this.entryError = '';
      try {
        await this.api(`/api/books/${this.ledgerBook}/gl-entries/${row.id}`, { method: 'DELETE' });
        await this.loadEntries();
      } catch (error) {
        this.entryError = error.message;
      }
    },
    // Import is a stateless two-step: upload the file for a dry-run preview (rows classified
    // new/update/duplicate/error), then commit the returned classified rows with the chosen strategy —
    // so the file is never re-uploaded and the server keeps no session between the two calls.
    async onImportFile(event) {
      const file = event.target.files[0];
      event.target.value = '';
      if (!file) return;
      this.entryError = '';
      this.message = '';
      try {
        const form = new FormData();
        form.append('file', file);
        const data = await (await this.api(`/api/books/${this.ledgerBook}/gl-entries/import/preview`, { method: 'POST', body: form })).json();
        this.importPreview = data;
        this.importStrategy = 'merge';
        this.importDialog = true;
      } catch (error) {
        this.entryError = `Import failed: ${error.message}`;
      }
    },
    async commitImport() {
      this.importing = true;
      try {
        const result = await (await this.api(`/api/books/${this.ledgerBook}/gl-entries/import/commit`, {
          method: 'POST',
          body: JSON.stringify({ rows: this.importPreview.rows, strategy: this.importStrategy })
        })).json();
        this.importDialog = false;
        this.message = `Imported: ${result.inserted} new, ${result.updated} updated, ${result.skipped} skipped${result.errors ? `, ${result.errors} error(s)` : ''}.`;
        await this.loadEntries();
      } catch (error) {
        this.entryError = error.message;
      } finally {
        this.importing = false;
      }
    },
    async exportEntries(format) {
      const blob = await (await this.api(`/api/books/${this.ledgerBook}/gl-entries/export?year=${this.ledgerYear}&format=${format}`)).blob();
      saveBlob(blob, `deprecore-${this.ledgerBook}-gl-entries.${format}`);
    },
    statusColor(status) {
      return { new: 'success', update: 'info', duplicate: 'warning', error: 'error' }[status] || undefined;
    },
    async openHistory(row) {
      this.historyRows = [];
      this.historyLoading = true;
      this.historyDialog = true;
      try {
        const data = await (await this.api(`/api/books/${this.ledgerBook}/gl-entries/${row.id}/history`)).json();
        this.historyRows = data.history;
      } catch (error) {
        this.entryError = error.message;
        this.historyDialog = false;
      } finally {
        this.historyLoading = false;
      }
    },
    // Field-level diff between an audit event's before/after snapshots.
    changedFields(before, after) {
      const norm = (v) => (v === null || v === undefined || v === '' ? '' : String(v));
      const b = before || {};
      const a = after || {};
      const out = [];
      for (const [key, label] of Object.entries(this.glFieldLabels)) {
        const from = norm(b[key]);
        const to = norm(a[key]);
        if (from !== to) out.push({ label, from: from || '—', to: to || '—' });
      }
      return out;
    },
    historyLabel(action) {
      return { create: 'Created', update: 'Updated', delete: 'Deleted' }[action] || action;
    },
    historyColor(action) {
      return { create: 'success', update: 'info', delete: 'error' }[action] || undefined;
    },
    // ---- Chart of accounts + posting defaults -------------------------------
    blankAccount() {
      return { id: null, code: '', name: '', type: 'asset', normal_balance: 'debit', description: '', active: true };
    },
    typeLabel(type) {
      return { asset: 'Asset', contra_asset: 'Contra-asset', liability: 'Liability', equity: 'Equity', revenue: 'Revenue', expense: 'Expense' }[type] || type;
    },
    async loadAccounts() {
      this.accountError = '';
      try {
        const data = await (await this.api('/api/gl-accounts')).json();
        this.accounts = data.accounts;
        this.defaults = { ...this.defaults, ...data.defaults };
      } catch (error) {
        this.accountError = error.message;
      }
    },
    openAccount(row) {
      this.accountForm = row ? { ...this.blankAccount(), ...row } : this.blankAccount();
      this.accountDialogError = '';
      this.accountDialog = true;
    },
    async saveAccount() {
      this.savingAccount = true;
      this.accountDialogError = '';
      this.accountMessage = '';
      try {
        const method = this.accountForm.id ? 'PUT' : 'POST';
        const url = this.accountForm.id ? `/api/gl-accounts/${this.accountForm.id}` : '/api/gl-accounts';
        await this.api(url, { method, body: JSON.stringify(this.accountForm) });
        this.accountDialog = false;
        await this.loadAccounts();
      } catch (error) {
        this.accountDialogError = error.message;
      } finally {
        this.savingAccount = false;
      }
    },
    async removeAccount(row) {
      if (!window.confirm(`Delete account ${row.code} — ${row.name}? The change is recorded in the audit trail.`)) return;
      this.accountError = '';
      try {
        await this.api(`/api/gl-accounts/${row.id}`, { method: 'DELETE' });
        await this.loadAccounts();
      } catch (error) {
        this.accountError = error.message;
      }
    },
    async saveDefaults() {
      this.savingDefaults = true;
      this.accountError = '';
      this.accountMessage = '';
      try {
        const data = await (await this.api('/api/gl-account-defaults', { method: 'PUT', body: JSON.stringify(this.defaults) })).json();
        this.defaults = { ...this.defaults, ...data.defaults };
        this.accountMessage = 'Posting defaults saved.';
        this.loadLedger(); // the ledger's fallback accounts changed — refresh it
      } catch (error) {
        this.accountError = error.message;
      } finally {
        this.savingDefaults = false;
      }
    }
  }
};
</script>

<style scoped>
.ledger-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.ledger-chip {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 140px;
  padding: 10px 14px;
  border: 1px solid rgba(128, 128, 128, 0.25);
  border-radius: 8px;
}
.ledger-chip strong {
  font-size: 1.05rem;
}
.gl-history-item {
  padding: 10px 0;
  border-bottom: 1px solid rgba(128, 128, 128, 0.2);
}
.gl-history-item:last-child {
  border-bottom: none;
}
.gl-diff {
  font-size: 0.85rem;
  border-collapse: collapse;
}
.gl-diff td {
  padding: 2px 6px;
  vertical-align: top;
}
.gl-from {
  color: rgb(var(--v-theme-error));
  text-decoration: line-through;
}
.gl-to {
  color: rgb(var(--v-theme-success));
}
</style>
