<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import DateTimePicker, { TabType } from '@/components/DateTimePicker.vue';
import { resolveLoopRules4UI, getDayInMonth } from '@/utils/datetime';
import { WEEK_NAMES } from '@/utils/calendar-names';
import { format } from '@/utils/utils';

type LoopMethod = 'never' | 'day' | 'week' | 'month' | 'year';
type StopMethod = 'forever' | 'datetime' | 'times';

const props = defineProps<{
  modelValue: string;
  startDate: Date;
}>();

const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void
}>();

const stopPicker = ref<InstanceType<typeof DateTimePicker>>();

const loopMethod = ref<LoopMethod>('never');
const daySpan = ref<number>(1);
const weekSpan = ref<number>(1);
const monthSpan = ref<number>(1);
const yearSpan = ref<number>(1);
// default: today's weekday checked (Monday-first 0-6)
const initialWeekday = (new Date().getDay() + 6) % 7;
const weekChecks = ref<boolean[]>(Array.from({ length: 7 }, (_, i) => i === initialWeekday));
const monthMode = ref<'A' | 'B' | 'C' | 'D'>('A');
const isStrict = ref<boolean>(true);
const stopMethod = ref<StopMethod>('forever');
const stopTimes = ref<number>(1);
const stopDateTime = ref<Date>(new Date());

// region: Serialize / parse

const buildString = (): string => {
  let loopPart = '';
  switch (loopMethod.value) {
    case 'never':
      return '';
    case 'day':
      loopPart = `D${daySpan.value}`;
      break;
    case 'week': {
      const checks = weekChecks.value.map(b => b ? 'T' : 'F').join('');
      loopPart = `W${checks}${weekSpan.value}`;
      break;
    }
    case 'month':
      loopPart = `M${isStrict.value ? 'S' : 'R'}${monthMode.value}${monthSpan.value}`;
      break;
    case 'year':
      loopPart = `Y${isStrict.value ? 'S' : 'R'}${yearSpan.value}`;
      break;
  }
  let stopPart = '';
  switch (stopMethod.value) {
    case 'forever':
      stopPart = '-F';
      break;
    case 'datetime':
      stopPart = `-D${Math.floor(stopDateTime.value.getTime() / 60000)}`;
      break;
    case 'times':
      stopPart = `-T${stopTimes.value}`;
      break;
  }
  return loopPart + stopPart;
};

const serialized = computed<string>(() => buildString());

// Cast helpers: the parsed rule tuples are a union; index access is loose here.
const parseFromModel = (val: string): void => {
  if (val === serialized.value) return;
  if (val === '') {
    loopMethod.value = 'never';
    return;
  }
  const parsed = resolveLoopRules4UI(val);
  if (typeof parsed === 'undefined') {
    loopMethod.value = 'never';
    return;
  }
  const loopRule = parsed[0];
  const stopRule = parsed[1];
  switch (loopRule[0]) {
    case 0:
      loopMethod.value = 'year';
      isStrict.value = loopRule[1];
      yearSpan.value = loopRule[2];
      break;
    case 1:
      loopMethod.value = 'month';
      isStrict.value = loopRule[1];
      monthMode.value = loopRule[2];
      monthSpan.value = loopRule[3];
      break;
    case 2:
      loopMethod.value = 'week';
      weekChecks.value = [loopRule[1], loopRule[2], loopRule[3], loopRule[4], loopRule[5], loopRule[6], loopRule[7]];
      weekSpan.value = loopRule[8];
      break;
    case 3:
      loopMethod.value = 'day';
      daySpan.value = loopRule[1];
      break;
  }
  switch (stopRule[0]) {
    case 0:
      stopMethod.value = 'forever';
      break;
    case 1:
      stopMethod.value = 'datetime';
      // NOTE: treated as a plain UTC instant (day-precision stop), deviating
      // from the legacy timezone-shifted display. See migration notes.
      stopDateTime.value = new Date(stopRule[1] * 60000);
      break;
    case 2:
      stopMethod.value = 'times';
      stopTimes.value = stopRule[1];
      break;
  }
};

watch(() => props.modelValue, (val) => parseFromModel(val), { immediate: true });
watch(serialized, (val) => {
  if (val !== props.modelValue) emit('update:modelValue', val);
});

// endregion

const showLoopStop = computed(() => loopMethod.value !== 'never');
const showStrictMode = computed(() => loopMethod.value === 'month' || loopMethod.value === 'year');

const monthOptionTexts = computed(() => {
  const d = getDayInMonth(
    props.startDate.getFullYear(),
    props.startDate.getMonth() + 1,
    props.startDate.getDate()
  );
  return {
    A: format('Day {0} in month', d[0]),
    B: format('Day {0} from the end of the month', d[1]),
    C: format('Day {1} in week {0}', d[2], d[3] + 1),
    D: format('Day {1} in week {0} from the end of the month', d[4], d[5] + 1),
  };
});

const stopDateTimeText = computed(() => stopDateTime.value.toLocaleDateString());

const openStopPicker = () => {
  stopPicker.value?.modal(stopDateTime.value, TabType.Day);
};

const onStopPickerConfirm = (date: Date) => {
  stopDateTime.value = date;
};
</script>

<template>
  <section class="section">
    <h2 class="subtitle">Event Loop</h2>
    <div class="button-list">
      <label class="radio">
        <input type="radio" value="never" v-model="loopMethod">
        <span>Never</span>
      </label>
      <label class="radio">
        <input type="radio" value="day" v-model="loopMethod">
        <span>Day</span>
      </label>
      <label class="radio">
        <input type="radio" value="week" v-model="loopMethod">
        <span>Week</span>
      </label>
      <label class="radio">
        <input type="radio" value="month" v-model="loopMethod">
        <span>Month</span>
      </label>
      <label class="radio">
        <input type="radio" value="year" v-model="loopMethod">
        <span>Year</span>
      </label>
    </div>

    <div v-if="loopMethod === 'day'">
      <div class="field">
        <label class="label">Day span</label>
        <div class="control">
          <input v-model.number="daySpan" class="input spanpicker" type="number" min="1" max="100" step="1">
        </div>
      </div>
    </div>

    <div v-if="loopMethod === 'week'">
      <div class="field">
        <label class="label">Week span</label>
        <div class="control">
          <input v-model.number="weekSpan" class="input spanpicker" type="number" min="1" max="100" step="1">
        </div>
      </div>
      <div class="field">
        <label class="label">Week options</label>
        <div class="button-list">
          <label v-for="(name, i) in WEEK_NAMES" :key="i" class="checkbox">
            <input type="checkbox" v-model="weekChecks[i]">
            <span>{{ name }}</span>
          </label>
        </div>
      </div>
    </div>

    <div v-if="loopMethod === 'month'">
      <div class="field">
        <label class="label">Month span</label>
        <div class="control">
          <input v-model.number="monthSpan" class="input spanpicker" type="number" min="1" max="100" step="1">
        </div>
      </div>
      <div class="field">
        <label class="label">Month mode</label>
        <div class="button-list">
          <label class="radio">
            <input type="radio" value="A" v-model="monthMode">
            <span>{{ monthOptionTexts.A }}</span>
          </label>
          <label class="radio">
            <input type="radio" value="B" v-model="monthMode">
            <span>{{ monthOptionTexts.B }}</span>
          </label>
          <label class="radio">
            <input type="radio" value="C" v-model="monthMode">
            <span>{{ monthOptionTexts.C }}</span>
          </label>
          <label class="radio">
            <input type="radio" value="D" v-model="monthMode">
            <span>{{ monthOptionTexts.D }}</span>
          </label>
        </div>
      </div>
    </div>

    <div v-if="loopMethod === 'year'">
      <div class="field">
        <label class="label">Year span</label>
        <div class="control">
          <input v-model.number="yearSpan" class="input spanpicker" type="number" min="1" max="100" step="1">
        </div>
      </div>
    </div>
  </section>

  <section v-if="showStrictMode" class="section">
    <h2 class="subtitle">Strict Mode in Event Loop</h2>
    <p>You can choose strict mode or rough mode in following content. This is only effect on looped event.</p>
    <div class="button-list">
      <label class="radio">
        <input type="radio" :value="true" v-model="isStrict">
        <span>Strict Mode. If ordered day is not existing, skip it.</span>
      </label>
      <label class="radio">
        <input type="radio" :value="false" v-model="isStrict">
        <span>Rough mode. If ordered day is not existing, choose the day closing with original day to arrange event.</span>
      </label>
    </div>
  </section>

  <section v-if="showLoopStop" class="section">
    <h2 class="subtitle">Event Loop Stop</h2>
    <div class="button-list">
      <label class="radio">
        <input type="radio" value="forever" v-model="stopMethod">
        <span>Forever</span>
      </label>
      <label class="radio">
        <input type="radio" value="datetime" v-model="stopMethod">
        <span>Date Time</span>
      </label>
      <label class="radio">
        <input type="radio" value="times" v-model="stopMethod">
        <span>Times</span>
      </label>
    </div>
    <div v-if="stopMethod === 'datetime'">
      <a class="button" @click="openStopPicker">
        <span>{{ stopDateTimeText }}</span>
      </a>
    </div>
    <div v-if="stopMethod === 'times'">
      <div class="field">
        <div class="control">
          <input v-model.number="stopTimes" class="input spanpicker" type="number" min="1" max="100" step="1">
        </div>
      </div>
    </div>
  </section>

  <DateTimePicker ref="stopPicker" @confirm="onStopPickerConfirm" />
</template>

<style scoped>
.section {
  border-top: 1px solid rgba(219, 219, 219, .5);
  padding-top: 1.25rem;
  margin-top: 1.25rem;
}
</style>
