<template>
  <div class="event-form">
    <h2>Veranstaltung Formular</h2>
    <form @submit.prevent="saveEvent">
      <table>
        <tbody>
          <tr>
            <td><label for="name">Name:</label></td>
            <td><input type="text" id="name" v-model="eventData.name" required></td>
          </tr>
          <tr>
            <td><label for="eventType">Typ:</label></td>
            <td>
              <multiselect v-model="selectedEventType" :options="eventTypes" label="caption" track-by="id"
                placeholder="Typ wählen"></multiselect>
            </td>
          </tr>
          <tr>
            <td><label for="dateMode">Datum-Modus:</label></td>
            <td>
              <select v-model="dateMode">
                <option value="date">Datum</option>
                <option value="weekday">Wochentag</option>
                <option value="interval">Intervall</option>
                <option value="bulk">Bulk-Datum</option>
              </select>
            </td>
          </tr>
          <tr v-if="dateMode === 'date' || dateMode === 'interval'">
            <td><label for="date">Datum:</label></td>
            <td>
              <input type="date" id="date" v-model="eventData.date">
            </td>
          </tr>
          <tr v-if="dateMode === 'bulk'">
            <td><label for="bulkDates">Bulk-Daten:</label></td>
            <td>
              <textarea id="bulkDates" v-model="bulkDates"
                placeholder="Mehrere Daten, z.B. 27.03.2025,03.04.2025 oder je Zeile ein Datum"></textarea>
              <div style="font-size: 0.9em; color: #888;">Format: TT.MM.JJJJ (optional weiterhin JJJJ-MM-TT). Trennen mit Komma oder Zeilenumbruch.</div>
            </td>
          </tr>
          <tr v-if="dateMode === 'weekday' || dateMode === 'interval'">
            <td><label for="dayOfWeek">Wochentag:</label></td>
            <td>
              <multiselect v-model="eventData.dayOfWeek" :options="weekdays" label="name" track-by="value"
                placeholder="Wochentag wählen"></multiselect>
            </td>
          </tr>
          <tr>
            <td><label for="time">Uhrzeit:</label></td>
            <td><input type="time" id="time" v-model="eventData.time"></td>
          </tr>
          <tr>
            <td><label for="endTime">Ende-Uhrzeit:</label></td>
            <td><input type="time" id="endTime" v-model="eventData.endTime"></td>
          </tr>
          <tr>
            <td><label for="description">Beschreibung:</label></td>
            <td><textarea id="description" v-model="eventData.description" class="descriptionedit"></textarea></td>
          </tr>
          <tr>
            <td><label for="institution">Institution:</label></td>
            <td>
              <multiselect v-model="selectedInstitution" :options="localInstitutions" label="name" track-by="id"
                placeholder="Institution wählen"></multiselect>
            </td>
          </tr>
          <tr>
            <td><label for="eventPlace">Veranstaltungsort:</label></td>
            <td>
              <multiselect v-model="selectedEventPlace" :options="localEventPlaces" label="name" track-by="id"
                placeholder="Veranstaltungsort wählen"></multiselect>
            </td>
          </tr>
          <tr>
            <td><label for="contactPersons">Kontaktpersonen:</label></td>
            <td>
              <multiselect v-model="selectedContactPersons" :options="localContactPersons" :multiple="true" label="name"
                track-by="id" placeholder="Kontaktpersonen wählen"></multiselect>
            </td>
          </tr>
          <tr>
            <td colspan="2"><label><input type="checkbox" v-model="onHomepage">Auf der Startseite anzeigen</label></td>
          </tr>
          <tr>
            <td>Zugewiesenes Bild:</td>
            <td>
              <div v-if="assignedImage != null && imageFilename">
                <img :src="getImagePath" class="preview-image" />
                <button @click="removeImage" type="button">Bild entfernen</button>
              </div>
              <div v-else>
                <button type="button" @click="openAddImageDialog">Bild auswählen</button>
              </div>
            </td>
          </tr>
          <tr>
            <td colspan="2">
              <button type="submit">Speichern</button>
            </td>
          </tr>
        </tbody>
      </table>
    </form>
  </div>
  <AddImageDialog ref="addImageDialog" @confirm="setImage" />
</template>

<script>
import axios from 'axios';
import Multiselect from 'vue-multiselect';
import { formatTime } from '@/utils/strings';
import AddImageDialog from '@/components/AddImageDialog.vue';

function normalizeDateForInput(value) {
  if (!value) return '';
  if (value instanceof Date && !Number.isNaN(value.getTime())) {
    const yyyy = value.getFullYear();
    const mm = String(value.getMonth() + 1).padStart(2, '0');
    const dd = String(value.getDate()).padStart(2, '0');
    return `${yyyy}-${mm}-${dd}`;
  }
  const raw = String(value).trim();
  // ISO oder SQL-Format: YYYY-MM-DD...
  const isoMatch = raw.match(/^(\d{4})-(\d{2})-(\d{2})/);
  if (isoMatch) {
    return `${isoMatch[1]}-${isoMatch[2]}-${isoMatch[3]}`;
  }
  // Deutsches Format: DD.MM.YYYY
  const deMatch = raw.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/);
  if (deMatch) {
    const dd = String(deMatch[1]).padStart(2, '0');
    const mm = String(deMatch[2]).padStart(2, '0');
    const yyyy = deMatch[3];
    return `${yyyy}-${mm}-${dd}`;
  }
  return '';
}

export default {
  name: 'EventForm',
  components: { Multiselect, AddImageDialog },
  props: {
    event: {
      type: Object,
      required: true,
      default: () => ({})
    },
    institutions: {
      type: Array,
      required: true,
      default: () => []
    },
    eventPlaces: {
      type: Array,
      required: true,
      default: () => []
    },
    contactPersons: {
      type: Array,
      required: true,
      default: () => []
    }
  },
  data() {
    return {
      eventData: {
        ...this.event,
        date: normalizeDateForInput(this.event?.date),
      },
      selectedEventType: null,
      selectedInstitution: this.event.institution || null,
      selectedEventPlace: this.event.eventPlace || null,
      selectedContactPersons: this.event.contactPersons || [],
      eventTypes: [],
      dateMode: 'date',
      weekdays: [
        { name: 'Montag', value: 1 },
        { name: 'Dienstag', value: 2 },
        { name: 'Mittwoch', value: 3 },
        { name: 'Donnerstag', value: 4 },
        { name: 'Freitag', value: 5 },
        { name: 'Samstag', value: 6 },
        { name: 'Sonntag', value: 7 },
      ],
      localInstitutions: [...this.institutions],
      localEventPlaces: [...this.eventPlaces],
      localContactPersons: [...this.contactPersons],
      onHomepage: false,
      assignedImage: null,
      imageFilename: '',
      bulkDates: '',
    };
  },
  watch: {
    event(newVal) {
      this.eventData = this.normalizeEventForForm(newVal);
      this.determineDateMode();
      if (newVal && typeof newVal.__newsletterDateMode === 'string') {
        this.dateMode = newVal.__newsletterDateMode;
      }
      if (newVal && typeof newVal.__newsletterBulkDates === 'string') {
        this.bulkDates = newVal.__newsletterBulkDates;
      }
      this.selectedEventType = this.eventTypes.find(type => type.id === newVal.eventTypeId) || null;
      this.selectedInstitution = newVal.institution || null;
      this.selectedEventPlace =
        newVal.eventPlace ||
        this.localEventPlaces.find((place) => place.id === newVal.event_place_id || place.id === newVal.eventPlaceId) ||
        null;
      this.selectedContactPersons = newVal.contactPersons || [];
      this.onHomepage = newVal.alsoOnHomepage == 1 ? true : false;
      this.assignedImage = newVal.relatedImage || null;
      if (this.assignedImage) {
        this.fetchImageFilename();
      }
    },
    institutions(newVal) {
      this.localInstitutions = [...newVal];
    },
    eventPlaces(newVal) {
      this.localEventPlaces = [...newVal];
    },
    contactPersons(newVal) {
      this.localContactPersons = [...newVal];
    }
  },
  async created() {
    try {
      const eventTypeResponse = await axios.get('/event-types');
      this.eventTypes = eventTypeResponse.data;
      this.selectedEventType = this.eventTypes.find(type => type.id === this.event.eventTypeId) || null;
      if (!this.selectedEventType && this.event?.eventTypeId) {
        this.selectedEventType = this.eventTypes.find(type => type.id === this.event.eventTypeId) || null;
      }
    } catch (error) {
      console.error('Failed to fetch event types:', error);
    }
    this.determineDateMode();
    if (this.event && typeof this.event.__newsletterDateMode === 'string') {
      this.dateMode = this.event.__newsletterDateMode;
    }
    if (this.event && typeof this.event.__newsletterBulkDates === 'string') {
      this.bulkDates = this.event.__newsletterBulkDates;
    }
  },
  computed: {
    getImagePath() {
      return this.imageFilename ? `/images/uploads/${this.imageFilename}` : '';
    }
  },
  methods: {
    formatTime,
    async saveEvent() {
      try {
        const dayOfWeekValue = this.extractDayOfWeekValue(this.eventData.dayOfWeek);
        const basePayload = {
          ...this.eventData,
          eventTypeId: this.selectedEventType ? this.selectedEventType.id : null,
          institution_id: this.selectedInstitution ? this.selectedInstitution.id : null,
          event_place_id: this.selectedEventPlace ? this.selectedEventPlace.id : null,
          contactPersonIds: this.selectedContactPersons.map(person => person.id),
          dayOfWeek: dayOfWeekValue,
          relatedImage: this.assignedImage,
          alsoOnHomepage: this.onHomepage ? 1 : 0
        };
        if (this.dateMode === 'bulk' && this.bulkDates) {
          // Aufteilen und deutsche Datumsformate (TT.MM.JJJJ) sowie ISO (JJJJ-MM-TT) akzeptieren
            const parts = this.bulkDates.split(/,|\n/).map(d => d.trim()).filter(d => d.length > 0);
            const isoDates = [];
            const invalid = [];
            const pad = n => n.toString().padStart(2, '0');
            for (const p of parts) {
              // dd.mm.yyyy
              let m = p.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/);
              if (m) {
                const dd = parseInt(m[1], 10);
                const mm = parseInt(m[2], 10);
                const yyyy = parseInt(m[3], 10);
                // einfache Plausibilitätsprüfung
                if (mm >= 1 && mm <= 12 && dd >= 1 && dd <= 31) {
                  isoDates.push(`${yyyy}-${pad(mm)}-${pad(dd)}`);
                  continue;
                } else {
                  invalid.push(p);
                  continue;
                }
              }
              // ISO yyyy-mm-dd
              if (/^\d{4}-\d{2}-\d{2}$/.test(p)) {
                isoDates.push(p);
              } else {
                invalid.push(p);
              }
            }
            if (isoDates.length === 0) {
              alert('Keine gültigen Datumsangaben erkannt. Erlaubt: TT.MM.JJJJ oder JJJJ-MM-TT');
              return;
            }
            if (invalid.length > 0) {
              // Hinweis für Benutzer über ignorierte Werte
              console.warn('Ungültige Datumsangaben ignoriert:', invalid);
              alert('Folgende Einträge wurden ignoriert: ' + invalid.join(', '));
            }
            const results = [];
            for (const date of isoDates) {
              const payload = { ...basePayload, date };
              const response = await axios.post('/events', payload);
              results.push(response.data);
            }
            this.$emit('saved', results);
        } else {
          let response;
          if (this.eventData.id) {
            response = await axios.put(`/events/${this.eventData.id}`, basePayload);
          } else {
            response = await axios.post('/events', basePayload);
          }
          this.$emit('saved', response.data);
        }
      } catch (error) {
        console.error('Failed to save event:', error);
      }
    },
    determineDateMode() {
      // Bei bestehenden Events hat dayOfWeek oft einen Wert, obwohl "Datum" gemeint ist.
      // Deshalb hat fixes Datum Vorrang vor Intervall.
      if (this.eventData.date) {
        this.dateMode = 'date';
      } else if (this.extractDayOfWeekValue(this.eventData.dayOfWeek) > -1) {
        this.dateMode = 'weekday';
      } else {
        this.dateMode = 'date';
      }
    },
    normalizeEventForForm(event) {
      const normalized = { ...(event || {}) };
      normalized.date = normalizeDateForInput(normalized.date);
      const dayValue = this.extractDayOfWeekValue(normalized.dayOfWeek);
      if (dayValue > -1) {
        const mappedValue = dayValue === 0 ? 7 : dayValue;
        normalized.dayOfWeek =
          this.weekdays.find((d) => d.value === mappedValue) || null;
      } else {
        normalized.dayOfWeek = null;
      }
      return normalized;
    },
    extractDayOfWeekValue(dayOfWeek) {
      if (dayOfWeek === null || dayOfWeek === undefined || dayOfWeek === '') {
        return -1;
      }
      if (typeof dayOfWeek === 'object') {
        if (dayOfWeek.value === null || dayOfWeek.value === undefined || dayOfWeek.value === '') {
          return -1;
        }
        return Number(dayOfWeek.value);
      }
      const parsed = Number(dayOfWeek);
      return Number.isFinite(parsed) ? parsed : -1;
    },
    async fetchImageFilename() {
      try {
        const response = await axios.get('/image/' + this.assignedImage);
        this.imageFilename = response.data.filename;
      } catch (error) {
        console.error('Bild konnte nicht geladen werden:', error);
      }
    },
    openAddImageDialog() {
      this.$refs.addImageDialog.openAddImageDialog();
    },

    async setImage(imageId) {
      this.assignedImage = imageId;
      try {
        const response = await axios.get('/image/' + imageId);
        this.imageFilename = response.data.filename;
      } catch (error) {
        console.error('Bild konnte nicht geladen werden:', error);
        this.imageFilename = '';
      }
    },

    removeImage() {
      this.assignedImage = null;
      this.imageFilename = '';
    },
    focusFirstField() {
      // Fokussiert das erste Eingabefeld (Name)
      this.$nextTick(() => {
        const nameInput = document.getElementById('name');
        if (nameInput) {
          nameInput.focus();
        }
      });
    }
  }
};
</script>

<style scoped>
@import 'vue-multiselect/dist/vue-multiselect.css';

.event-form {
  max-width: 600px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
}

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

td {
  padding: 8px;
  vertical-align: top;
}

label {
  display: block;
}

button {
  margin-top: 20px;
}

.descriptionedit {
  width: 100%;
  height: 10em;
}

.preview-image {
  max-width: 50px;
  max-height: 50px;
  object-fit: contain;
}
</style>
