<template>
  <BaseDialog
    :model-value="modelValue"
    @update:model-value="$emit('update:modelValue', $event)"
    title="TTR-Historie"
    size="large"
    :width="1170"
    max-width="95vw"
    @close="closeDialog"
  >
    <div class="ttr-history-content">
      <div class="dialog-intro">
        <div>
          <div class="member-name">{{ memberName }}</div>
        </div>
        <div class="meta-block">
          <span class="meta-label">Letzter Abruf</span>
          <span class="meta-value">{{ formatDateTime(lastFetchedAt) }}</span>
        </div>
      </div>

      <div class="filter-row">
        <label class="filter-label" for="ttr-history-range">Zeitraum</label>
        <select id="ttr-history-range" v-model="selectedRange" class="filter-select">
          <option v-for="option in rangeOptions" :key="option.value" :value="option.value">
            {{ option.label }}
          </option>
        </select>
      </div>

      <div v-if="loading" class="state-panel">Historie wird geladen...</div>
      <div v-else-if="errorMessage && entries.length === 0" class="state-panel state-panel-error">{{ errorMessage }}</div>
      <div v-else class="content-grid">
        <div v-if="refreshing" class="state-panel state-panel-info">
          Historie wird im Hintergrund aktualisiert...
        </div>
        <div v-if="errorMessage" class="state-panel state-panel-error state-panel-full">{{ errorMessage }}</div>
        <div v-if="infoMessage" class="state-panel state-panel-info">{{ infoMessage }}</div>

        <div class="chart-panel">
          <div class="panel-title">Verlauf</div>
          <div v-if="chartPoints.length < 2" class="state-panel state-panel-muted">
            Noch nicht genug Datenpunkte für einen Verlauf.
          </div>
          <svg
            v-else
            class="history-chart"
            :viewBox="`0 0 ${chartMeta.width} ${chartMeta.height}`"
            preserveAspectRatio="none"
            aria-label="TTR-Verlauf"
          >
            <line
              class="chart-axis"
              :x1="chartMeta.paddingLeft"
              :y1="chartMeta.height - chartMeta.paddingBottom"
              :x2="chartMeta.width - chartMeta.paddingRight"
              :y2="chartMeta.height - chartMeta.paddingBottom"
            />
            <line
              class="chart-axis"
              :x1="chartMeta.paddingLeft"
              :y1="chartMeta.paddingTop"
              :x2="chartMeta.paddingLeft"
              :y2="chartMeta.height - chartMeta.paddingBottom"
            />
            <g v-for="tick in chartYTicks" :key="`y-${tick.value}`">
              <line
                class="chart-grid-line"
                :x1="chartMeta.paddingLeft"
                :y1="tick.y"
                :x2="chartMeta.width - chartMeta.paddingRight"
                :y2="tick.y"
              />
              <text class="chart-y-label" :x="chartMeta.paddingLeft - 10" :y="tick.y + 4">
                {{ tick.label }}
              </text>
            </g>
            <polyline class="chart-line" :points="chartPolyline" />
            <circle
              v-for="point in chartPoints"
              :key="point.id"
              class="chart-point"
              :cx="point.x"
              :cy="point.y"
              r="4"
            />
            <g v-for="tick in chartXTicks" :key="`x-${tick.id}`">
              <line
                class="chart-tick"
                :x1="tick.x"
                :y1="chartMeta.height - chartMeta.paddingBottom"
                :x2="tick.x"
                :y2="chartMeta.height - chartMeta.paddingBottom + 6"
              />
              <text
                class="chart-x-label"
                :transform="`translate(${tick.x + 6}, ${chartMeta.height - chartMeta.paddingBottom + 12}) rotate(90)`"
              >
                {{ tick.label }}
              </text>
            </g>
          </svg>
        </div>

        <div class="table-panel">
          <div class="panel-title">Historie</div>
          <div v-if="tableRows.length === 0" class="state-panel state-panel-muted">
            Noch keine gespeicherte TTR-Historie vorhanden.
          </div>
          <table v-else class="history-table">
            <thead>
              <tr>
                <th>Datum</th>
                <th>TTR</th>
                <th>Veränderung</th>
                <th>Quelle</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="row in tableRows" :key="row.id">
                <td>{{ formatDate(row.sourceDate) }}</td>
                <td class="ttr-transition-cell">{{ formatTtrTransition(row.beforeTtr, row.afterTtr) }}</td>
                <td :class="changeClass(row.change)">
                  {{ formatChange(row.change) }}
                </td>
                <td>{{ row.label || row.sourceType || '–' }}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>

    <template #footer>
      <button type="button" class="btn-secondary" @click="closeDialog">Schließen</button>
    </template>
  </BaseDialog>
</template>

<script>
import BaseDialog from './BaseDialog.vue';
import apiClient from '../apiClient.js';
import { getSafeErrorMessage } from '../utils/errorMessages.js';

export default {
  name: 'MemberTtrHistoryDialog',
  components: {
    BaseDialog
  },
  props: {
    modelValue: {
      type: Boolean,
      default: false
    },
    member: {
      type: Object,
      required: true
    },
    clubId: {
      type: [String, Number],
      required: true
    }
  },
  emits: ['update:modelValue'],
  data() {
    return {
      loading: false,
      refreshing: false,
      errorMessage: '',
      infoMessage: '',
      entries: [],
      lastFetchedAt: null,
      selectedRange: 'all',
      playerId: this.member?.myTischtennisHistoryPlayerId || this.member?.myTischtennisPlayerId || null
    };
  },
  computed: {
    memberName() {
      return `${this.member?.firstName || ''} ${this.member?.lastName || ''}`.trim() || 'Mitglied';
    },
    chartMeta() {
      return {
        width: 760,
        height: 320,
        paddingTop: 24,
        paddingRight: 24,
        paddingBottom: 88,
        paddingLeft: 62
      };
    },
    rangeOptions() {
      return [
        { value: 'all', label: 'Alle' },
        { value: '36m', label: '3 Jahre' },
        { value: '24m', label: '2 Jahre' },
        { value: '12m', label: '1 Jahr' },
        { value: '9m', label: '9 Monate' },
        { value: '6m', label: '6 Monate' },
        { value: '3m', label: '3 Monate' },
        { value: '2m', label: '2 Monate' },
        { value: '1m', label: '1 Monat' }
      ];
    },
    filteredEntries() {
      if (this.selectedRange === 'all') {
        return this.entries;
      }

      const monthCount = Number.parseInt(this.selectedRange.replace('m', ''), 10);
      if (!Number.isFinite(monthCount)) {
        return this.entries;
      }

      const cutoff = new Date();
      cutoff.setHours(0, 0, 0, 0);
      cutoff.setMonth(cutoff.getMonth() - monthCount);

      return this.entries.filter((entry) => {
        if (!entry?.sourceDate) {
          return false;
        }
        const date = new Date(entry.sourceDate);
        return !Number.isNaN(date.getTime()) && date >= cutoff;
      });
    },
    tableRows() {
      return this.filteredEntries.map((entry, index) => {
        const previousEntry = this.filteredEntries[index + 1] || null;
        const beforeTtr = Number.isFinite(previousEntry?.ttr) ? previousEntry.ttr : null;
        const afterTtr = Number.isFinite(entry?.ttr) ? entry.ttr : null;
        const change = Number.isFinite(beforeTtr) && Number.isFinite(afterTtr)
          ? afterTtr - beforeTtr
          : null;

        return {
          ...entry,
          beforeTtr,
          afterTtr,
          change
        };
      });
    },
    chartPoints() {
      if (this.filteredEntries.length < 2) {
        return [];
      }

      const chronological = [...this.filteredEntries]
        .reverse()
        .map((entry) => ({
          ...entry,
          value: entry.ttr
        }))
        .filter((entry) => Number.isFinite(entry.value));

      if (chronological.length < 2) {
        return [];
      }

      const { width, height, paddingTop, paddingRight, paddingBottom, paddingLeft } = this.chartMeta;
      const values = chronological.map((entry) => entry.value);
      const minValue = Math.min(...values);
      const maxValue = Math.max(...values);
      const valueRange = Math.max(maxValue - minValue, 1);

      return chronological.map((entry, index) => {
        const ratioX = chronological.length === 1 ? 0.5 : index / (chronological.length - 1);
        const ratioY = (entry.value - minValue) / valueRange;
        return {
          id: entry.id,
          label: this.formatDate(entry.sourceDate),
          value: entry.value,
          x: paddingLeft + ratioX * (width - paddingLeft - paddingRight),
          y: height - paddingBottom - ratioY * (height - paddingTop - paddingBottom)
        };
      });
    },
    chartPolyline() {
      return this.chartPoints.map((point) => `${point.x},${point.y}`).join(' ');
    },
    chartXTicks() {
      if (this.chartPoints.length === 0) {
        return [];
      }

      if (this.chartPoints.length <= 12) {
        return this.chartPoints;
      }

      const usableWidth = this.chartMeta.width - this.chartMeta.paddingLeft - this.chartMeta.paddingRight;
      const estimatedLabelSpace = 70;
      const maxTicks = Math.min(
        this.chartPoints.length,
        Math.max(2, Math.floor(usableWidth / estimatedLabelSpace))
      );

      if (this.chartPoints.length <= maxTicks) {
        return this.chartPoints;
      }

      const step = Math.ceil((this.chartPoints.length - 1) / (maxTicks - 1));
      const ticks = this.chartPoints.filter((_, index) => index % step === 0);
      const lastPoint = this.chartPoints[this.chartPoints.length - 1];

      if (!ticks.some((tick) => tick.id === lastPoint.id)) {
        ticks.push(lastPoint);
      }

      return ticks;
    },
    chartYTicks() {
      if (this.chartPoints.length === 0) {
        return [];
      }

      const values = this.chartPoints.map((point) => point.value);
      const minValue = Math.min(...values);
      const maxValue = Math.max(...values);
      const steps = 4;
      const range = Math.max(maxValue - minValue, 1);
      const { height, paddingTop, paddingBottom } = this.chartMeta;
      const usableHeight = height - paddingTop - paddingBottom;

      return Array.from({ length: steps + 1 }, (_, index) => {
        const value = minValue + (range * index) / steps;
        const ratioY = (value - minValue) / range;
        return {
          value: `${index}-${Math.round(value)}`,
          label: Math.round(value),
          y: height - paddingBottom - ratioY * usableHeight
        };
      }).reverse();
    }
  },
  mounted() {
    if (this.modelValue) {
      this.openDialog();
    }
  },
  watch: {
    modelValue(newValue) {
      if (newValue) {
        this.openDialog();
      }
    },
    member: {
      deep: true,
      handler(newMember) {
        this.playerId = newMember?.myTischtennisHistoryPlayerId || newMember?.myTischtennisPlayerId || null;
        this.selectedRange = 'all';
      }
    }
  },
  methods: {
    closeDialog() {
      this.$emit('update:modelValue', false);
    },
    async openDialog() {
      await this.loadHistory();
      await this.refreshHistory({ silentStart: false });
    },
    async loadHistory(options = {}) {
      const { preserveMessages = false } = options;
      this.loading = true;
      if (!preserveMessages) {
        this.errorMessage = '';
        this.infoMessage = '';
      }
      try {
        const response = await apiClient.get(`/clubmembers/ttr-history/${this.clubId}/${this.member.id}`);
        this.entries = Array.isArray(response.data?.history) ? response.data.history : [];
        this.lastFetchedAt = response.data?.meta?.lastFetchedAt || null;
        this.playerId = response.data?.member?.myTischtennisHistoryPlayerId || response.data?.member?.myTischtennisPlayerId || this.playerId;
      } catch (error) {
        this.errorMessage = getSafeErrorMessage(error, 'TTR-Historie konnte nicht geladen werden.');
      } finally {
        this.loading = false;
      }
    },
    async refreshHistory(options = {}) {
      const { silentStart = false } = options;
      this.refreshing = true;
      if (!silentStart) {
        this.errorMessage = '';
        this.infoMessage = '';
      }
      try {
        const response = await apiClient.post(`/clubmembers/ttr-history/${this.clubId}/${this.member.id}/refresh`);
        if (response.data?.error) {
          this.errorMessage = response.data.error;
          return;
        }
        if (response.data?.skipped && response.data?.message) {
          this.infoMessage = response.data.message;
          this.lastFetchedAt = response.data?.meta?.lastFetchedAt || this.lastFetchedAt;
          return;
        }
        await this.loadHistory({ preserveMessages: true });
        if (response.data?.message) {
          this.infoMessage = response.data.message;
        }
      } catch (error) {
        this.errorMessage = getSafeErrorMessage(error, 'TTR-Historie konnte nicht aktualisiert werden.');
      } finally {
        this.refreshing = false;
      }
    },
    formatDate(value) {
      if (!value) {
        return '–';
      }
      const date = new Date(value);
      if (Number.isNaN(date.getTime())) {
        return value;
      }
      return date.toLocaleDateString('de-DE');
    },
    formatDateTime(value) {
      if (!value) {
        return 'Noch nie';
      }
      const date = new Date(value);
      if (Number.isNaN(date.getTime())) {
        return value;
      }
      return date.toLocaleString('de-DE');
    },
    formatTtrTransition(before, after) {
      if (!Number.isFinite(after)) {
        return '–';
      }
      if (!Number.isFinite(before)) {
        return `– -> ${after}`;
      }
      return `${before} -> ${after}`;
    },
    formatChange(value) {
      if (!Number.isFinite(value) || value === 0) {
        return '±0';
      }
      return value > 0 ? `+${value}` : `${value}`;
    },
    changeClass(value) {
      if (!Number.isFinite(value) || value === 0) {
        return 'change-neutral';
      }
      return value > 0 ? 'change-positive' : 'change-negative';
    }
  }
};
</script>

<style scoped>
.ttr-history-content {
  padding: 1rem;
}

.dialog-intro {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}

.member-name {
  font-size: 1.1rem;
  font-weight: 600;
  color: #203040;
}

.meta-block {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 180px;
}

.meta-label {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #7b8794;
}

.meta-value {
  color: #203040;
  font-weight: 600;
}

.filter-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.filter-label {
  font-weight: 600;
  color: #2c3e50;
}

.filter-select {
  min-width: 150px;
  padding: 0.55rem 0.85rem;
  border: 1px solid #d6dde6;
  border-radius: 8px;
  background: #fff;
  color: #203040;
  font-size: 0.95rem;
}

.content-grid {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 18px;
}

.chart-panel,
.table-panel {
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  border-radius: 16px;
  padding: 16px;
}

.panel-title {
  font-weight: 700;
  color: #1f2d3d;
  margin-bottom: 12px;
}

.state-panel {
  padding: 18px;
  border-radius: 12px;
  background: #f8fafc;
  color: #415164;
}

.state-panel-error {
  background: #fff1f0;
  color: #8b1e1e;
}

.state-panel-info {
  background: #eff6ff;
  color: #1d4ed8;
  grid-column: 1 / -1;
}

.state-panel-full {
  grid-column: 1 / -1;
}

.state-panel-muted {
  background: #f4f7fb;
  color: #66788a;
}

.history-chart {
  width: 100%;
  height: 320px;
  background: linear-gradient(180deg, #ffffff 0%, #f7fafc 100%);
  border-radius: 12px;
}

.chart-axis {
  stroke: #94a3b8;
  stroke-width: 1.5;
}

.chart-grid-line {
  stroke: #e2e8f0;
  stroke-width: 1;
}

.chart-line {
  fill: none;
  stroke: #1f6feb;
  stroke-width: 3;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.chart-point {
  fill: #0d4f9a;
}

.chart-tick {
  stroke: #94a3b8;
  stroke-width: 1;
}

.chart-x-label,
.chart-y-label {
  fill: #475569;
  font-size: 11px;
}

.chart-y-label {
  text-anchor: end;
}

.history-table {
  width: 100%;
  border-collapse: collapse;
}

.history-table th,
.history-table td {
  text-align: left;
  padding: 10px 8px;
  border-bottom: 1px solid #e5ebf3;
}

.history-table thead th {
  color: #fff;
  border-bottom: 2px solid #ddd;
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.ttr-transition-cell {
  white-space: nowrap;
}

.change-positive {
  color: #1f7a1f;
  font-weight: 700;
}

.change-negative {
  color: #c0392b;
  font-weight: 700;
}

.change-neutral {
  color: #475569;
  font-weight: 600;
}

.btn-secondary {
  border: none;
  border-radius: 10px;
  cursor: pointer;
  padding: 10px 16px;
  font-weight: 600;
}

.btn-secondary {
  background: #eef2f7;
  color: #203040;
}

@media (max-width: 900px) {
  .dialog-intro {
    flex-direction: column;
  }

  .filter-row {
    flex-direction: column;
    align-items: flex-start;
  }

  .content-grid {
    grid-template-columns: 1fr;
  }
}
</style>
