<template>
  <section class="content-grid">
    <!-- Report picker -->
    <v-card class="span-4 panel-pad">
      <h2 class="section-title mb-2">Reports</h2>
      <v-list v-model:opened="openGroups" density="compact" nav>
        <v-list-group v-for="group in groupedReports" :key="group.name" :value="group.name">
          <template #activator="{ props }">
            <v-list-item v-bind="props" :title="group.label" class="report-group-header" />
          </template>
          <v-list-item
            v-for="report in group.reports"
            :key="report.key"
            :active="selectedType === report.key"
            :title="report.title"
            rounded="sm"
            @click="selectReport(report.key)"
          />
        </v-list-group>
      </v-list>

      <template v-if="savedReports.length">
        <v-divider class="my-3" />
        <h3 class="section-title mb-2">Saved reports</h3>
        <v-list density="compact">
          <v-list-item v-for="saved in savedReports" :key="saved.id" :title="saved.name" :subtitle="saved.report_type" @click="applySaved(saved)">
            <template #append>
              <v-btn icon="mdi-delete-outline" size="x-small" variant="text" color="error" @click.stop="deleteSaved(saved.id)" />
            </template>
          </v-list-item>
        </v-list>
      </template>
    </v-card>

    <!-- Report output -->
    <v-card class="span-8 panel-pad">
      <div class="toolbar-row mb-3" style="flex-wrap:wrap;gap:10px">
        <template v-for="key in currentParams" :key="key">
          <v-select
            v-if="paramSpec(key).type === 'select'"
            v-model="options[key]"
            :items="normalizeOptions(paramSpec(key).options)"
            :label="paramSpec(key).label"
            :clearable="paramSpec(key).clearable"
            item-title="title"
            item-value="value"
            density="compact"
            hide-details
            style="max-width:200px"
            @update:model-value="run"
          />
          <v-select
            v-else-if="paramSpec(key).type === 'multiselect'"
            v-model="options[key]"
            :items="normalizeOptions(paramSpec(key).options)"
            :label="paramSpec(key).label"
            item-title="title"
            item-value="value"
            density="compact"
            hide-details
            chips
            multiple
            closable-chips
            style="min-width:280px"
            @update:model-value="run"
          />
          <v-text-field
            v-else-if="paramSpec(key).type === 'date'"
            v-model="options[key]"
            :label="paramSpec(key).label"
            type="date"
            density="compact"
            hide-details
            style="max-width:180px"
            @update:model-value="run"
          />
          <v-text-field
            v-else
            v-model.number="options[key]"
            :label="paramSpec(key).label"
            type="number"
            density="compact"
            hide-details
            style="max-width:130px"
            @update:model-value="run"
          />
        </template>
        <v-spacer />
        <v-btn variant="tonal" size="small" prepend-icon="mdi-content-save-outline" @click="openSave">Save</v-btn>
        <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="exportReport(format)" />
          </v-list>
        </v-menu>
      </div>

      <div v-if="report">
        <div class="toolbar-row mb-2">
          <h2 class="section-title">{{ report.title }}</h2>
          <v-spacer />
          <span class="quiet text-caption">{{ report.rows.length }} row(s)</span>
        </div>
        <v-alert v-if="report.meta && report.meta.note" type="info" density="compact" variant="tonal" class="mb-3">{{ report.meta.note }}</v-alert>

        <div v-if="report.meta && report.meta.asset" class="form-grid mb-3">
          <div v-for="(value, key) in report.meta.asset" :key="key">
            <div class="quiet text-caption">{{ key.replace(/_/g, ' ') }}</div>
            <div class="text-body-2 font-weight-medium">{{ value || '—' }}</div>
          </div>
        </div>

        <div v-if="report.chart" class="chart-box mb-4">
          <Bar :data="chartData" :options="chartOptions" />
        </div>

        <DataTable
          v-if="report.columns.length"
          :columns="report.columns"
          :totals="hasTotals ? report.totals : null"
          :rows="report.rows"
          searchable
          search-placeholder="Filter this report"
          empty-text="No data for the selected options."
        />

        <template v-if="report.meta && report.meta.sections">
          <div v-for="section in report.meta.sections" :key="section.title" class="mt-5">
            <h3 class="section-title mb-2">{{ section.title }}</h3>
            <DataTable
              :columns="section.columns"
              :rows="section.rows"
              :empty-text="`No ${section.title.toLowerCase()} recorded.`"
            />
          </div>
        </template>

        <div v-if="report.meta && report.meta.photo_count" class="mt-5">
          <h3 class="section-title mb-2">Photos ({{ report.meta.photo_count }})</h3>
          <p class="quiet text-body-2">
            <span v-if="report.meta.photos && report.meta.photos.length">{{ report.meta.photos.map((p) => p.caption).join(' · ') }}</span>
            <span v-else>—</span>
          </p>
          <p class="quiet text-caption">Photo thumbnails are embedded in the PDF / print export.</p>
        </div>
      </div>
      <div v-else class="quiet text-body-2">Select a report to begin.</div>

      <v-alert v-if="error" type="error" density="compact" class="mt-3">{{ error }}</v-alert>
    </v-card>

    <v-dialog v-model="saveDialog" max-width="440">
      <v-card>
        <v-card-title>Save report</v-card-title>
        <v-card-text>
          <v-text-field v-model="saveName" label="Report name" autofocus />
          <div class="quiet text-caption">{{ report ? report.title : '' }} · current options will be saved.</div>
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="saveDialog = false">Cancel</v-btn>
          <v-btn color="primary" :disabled="!saveName" @click="saveReport">Save</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </section>
</template>

<script>
import { Bar } from 'vue-chartjs';
import '../utils/charts';
import DataTable from '../components/DataTable.vue';
import { apiRequest, saveBlob } from '../services/api';

export default {
  components: { Bar, DataTable },
  props: {
    token: { type: String, required: true }
  },
  data() {
    return {
      reports: [],
      params: {},
      openGroups: [],
      selectedType: null,
      options: {},
      report: null,
      savedReports: [],
      saveDialog: false,
      saveName: '',
      error: '',
      chartOptions: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: { legend: { display: false } },
        scales: { y: { beginAtZero: true, ticks: { callback: (value) => `$${Number(value).toLocaleString()}` } } }
      }
    };
  },
  computed: {
    groupedReports() {
      // Desired display order, and friendlier labels for two catalog groups.
      const order = ['Depreciation', 'Activity', 'Journal entries', 'Tax', 'Maintenance', 'Detail', 'Journals & registers', 'Transactions', 'Summaries'];
      const labels = { 'Journal entries': 'Journal Entries', Maintenance: 'Preventative Maintenance', 'Journals & registers': 'Journals and Registers' };
      const rank = (name) => { const i = order.indexOf(name); return i === -1 ? order.length : i; };
      const groups = {};
      for (const report of this.reports) {
        groups[report.group] = groups[report.group] || [];
        groups[report.group].push(report);
      }
      return Object.keys(groups)
        .sort((a, b) => rank(a) - rank(b) || a.localeCompare(b))
        .map((name) => ({ name, label: labels[name] || name, reports: groups[name] }));
    },
    currentParams() {
      return this.reports.find((report) => report.key === this.selectedType)?.params || [];
    },
    hasTotals() {
      return this.report && this.report.totals && Object.keys(this.report.totals).length > 0;
    },
    chartData() {
      const chart = this.report?.chart;
      if (!chart) return { labels: [], datasets: [] };
      return {
        labels: chart.labels,
        datasets: [{ data: chart.values, backgroundColor: '#2457a6' }]
      };
    }
  },
  mounted() {
    this.loadCatalog();
    this.loadSavedReports();
  },
  methods: {
    async api(path, options = {}) {
      return apiRequest(path, this.token, options);
    },
    async loadCatalog() {
      try {
        const data = await (await this.api('/api/reports/catalog')).json();
        this.reports = data.reports;
        this.params = data.params;
        if (this.reports.length) this.selectReport(this.reports[0].key);
      } catch (error) {
        this.error = error.message;
      }
    },
    async loadSavedReports() {
      const data = await (await this.api('/api/saved-reports')).json();
      this.savedReports = data.reports;
    },
    paramSpec(key) {
      return this.params[key] || { label: key, type: 'text' };
    },
    normalizeOptions(options) {
      return (options || []).map((option) => (typeof option === 'object' ? option : { title: String(option), value: option }));
    },
    defaultOptions(type) {
      const report = this.reports.find((item) => item.key === type);
      const options = {};
      for (const key of report?.params || []) {
        const spec = this.paramSpec(key);
        options[key] = Array.isArray(spec.default) ? [...spec.default] : spec.default;
      }
      return options;
    },
    selectReport(type) {
      this.selectedType = type;
      this.options = this.defaultOptions(type);
      this.run();
    },
    openGroupFor(type) {
      const report = this.reports.find((item) => item.key === type);
      if (report && !this.openGroups.includes(report.group)) this.openGroups.push(report.group);
    },
    applySaved(saved) {
      this.selectedType = saved.report_type;
      this.options = { ...this.defaultOptions(saved.report_type), ...(saved.options_json || {}) };
      this.openGroupFor(saved.report_type);
      this.run();
    },
    async run() {
      if (!this.selectedType) return;
      this.error = '';
      try {
        const data = await (await this.api('/api/reports/run', {
          method: 'POST',
          body: JSON.stringify({ type: this.selectedType, options: this.options })
        })).json();
        this.report = data.report;
      } catch (error) {
        this.error = error.message;
      }
    },
    async exportReport(format) {
      const blob = await (await this.api('/api/reports/export', {
        method: 'POST',
        body: JSON.stringify({ type: this.selectedType, options: this.options, format })
      })).blob();
      saveBlob(blob, `deprecore-${this.selectedType}.${format}`);
    },
    openSave() {
      this.saveName = this.report?.title || 'Saved report';
      this.saveDialog = true;
    },
    async saveReport() {
      await this.api('/api/saved-reports', {
        method: 'POST',
        body: JSON.stringify({ name: this.saveName, report_type: this.selectedType, options: this.options })
      });
      this.saveDialog = false;
      await this.loadSavedReports();
    },
    async deleteSaved(id) {
      await this.api(`/api/saved-reports/${id}`, { method: 'DELETE' });
      await this.loadSavedReports();
    }
  }
};
</script>

<style scoped>
.report-group-header :deep(.v-list-item-title) {
  font-weight: 600;
}
</style>
