import type { Meta, StoryObj } from '@storybook/vue3-vite';
import { CalendarDate, getLocalTimeZone, today } from '@internationalized/date';
import type { DateRange, DateValue } from 'reka-ui';
import { ref, watch } from 'vue';
import UiDatePicker from './UiDatePicker.vue';

const meta: Meta<typeof UiDatePicker> = {
  title: 'Patterns/UiDatePicker',
  component: UiDatePicker,
  tags: ['autodocs'],
  decorators: [
    () => ({
      template: '<div class="inline-block"><story /></div>',
    }),
  ],
  argTypes: {
    mode: {
      control: 'select',
      options: ['single', 'range'],
      description: 'The selection mode: single date or date range.',
    },
    placeholder: {
      control: 'text',
      description: 'Placeholder text when no date is selected.',
    },
    disabled: {
      control: 'boolean',
      description: 'Whether the date picker is disabled.',
    },
    readonly: {
      control: 'boolean',
      description: 'Whether the date picker is read-only.',
    },
    locale: {
      control: 'select',
      options: ['en', 'de', 'fr', 'es', 'pl'],
      description: 'The locale to use for formatting dates.',
    },
    weekStartsOn: {
      control: 'select',
      options: [0, 1, 2, 3, 4, 5, 6],
      description:
        'The day of the week to start on. 0 is the locale default first day.',
    },
    numberOfMonths: {
      control: { type: 'number', min: 1, max: 3 },
      description: 'The number of months to display at once.',
    },
    pagedNavigation: {
      control: 'boolean',
      description:
        'Whether to navigate by page (all visible months) or by single month. Only applies in range mode.',
    },
    weekdayFormat: {
      control: 'select',
      options: ['narrow', 'short', 'long'],
      description: 'The format to use for weekday labels.',
    },
    fixedWeeks: {
      control: 'boolean',
      description: 'Whether to always show 6 weeks in the calendar.',
    },
    layout: {
      control: 'select',
      options: [undefined, 'month-and-year', 'month-only', 'year-only'],
      description:
        'Layout mode for the calendar header dropdowns. Only applies in single mode.',
    },
    preventDeselect: {
      control: 'boolean',
      description: 'Whether to prevent deselecting a date.',
    },
    closeOnSelect: {
      control: 'boolean',
      description:
        'Whether to close the popover after selecting a date (or date range).',
    },
  },
  args: {
    mode: 'single',
    disabled: false,
    readonly: false,
    locale: 'en',
    weekStartsOn: 0,
    numberOfMonths: 1,
    pagedNavigation: false,
    weekdayFormat: 'narrow',
    fixedWeeks: false,
    layout: undefined,
    preventDeselect: false,
    closeOnSelect: true,
  },
};

export default meta;

type Story = StoryObj<typeof UiDatePicker>;

const defaultTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateValue } from '@internationalized/date'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const date = ref<DateValue>()
</script>

<template>
  <UiDatePicker v-model="date" />
</template>`;

/**
 * Basic date picker with default settings.
 * Click the button to open the calendar and select a date.
 */
export const Default: Story = {
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const date = ref<DateValue>();
      watch(
        () => args.modelValue,
        (val) => {
          date.value = val;
        },
      );
      return { date, args };
    },
    template: `<UiDatePicker
      v-model="date"
      :placeholder="args.placeholder"
      :disabled="args.disabled"
      :readonly="args.readonly"
      :locale="args.locale"
      :week-starts-on="args.weekStartsOn"
      :number-of-months="args.numberOfMonths"
      :weekday-format="args.weekdayFormat"
      :fixed-weeks="args.fixedWeeks"
      :layout="args.layout"
      :prevent-deselect="args.preventDeselect"
      :close-on-select="args.closeOnSelect"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: defaultTemplateSource,
      },
    },
  },
};

const withPreselectedDateTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateValue } from '@internationalized/date'
import { getLocalTimeZone, today } from '@internationalized/date'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const date = ref<DateValue>(today(getLocalTimeZone()))
</script>

<template>
  <UiDatePicker v-model="date" />
</template>`;

/**
 * Date picker with a pre-selected date (today).
 */
export const WithPreselectedDate: Story = {
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const date = ref<DateValue>(today(getLocalTimeZone()));
      return { date, args };
    },
    template: `<UiDatePicker
      v-model="date"
      :locale="args.locale"
      :disabled="args.disabled"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: withPreselectedDateTemplateSource,
      },
    },
  },
};

const withMonthYearDropdownsTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateValue } from '@internationalized/date'
import { CalendarDate } from '@internationalized/date'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const date = ref<DateValue>()
const minValue = new CalendarDate(1925, 1, 1)
const maxValue = new CalendarDate(2035, 1, 1)
</script>

<template>
  <UiDatePicker
    v-model="date"
    layout="month-and-year"
    :min-value="minValue"
    :max-value="maxValue"
    placeholder="Select birth date"
  />
</template>`;

/**
 * Date picker with month and year dropdown selectors.
 * Useful for date-of-birth pickers or when users need to navigate far from the current date.
 */
export const WithMonthYearDropdowns: Story = {
  args: {
    layout: 'month-and-year',
    placeholder: 'Select birth date',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const date = ref<DateValue>();
      const minValue = new CalendarDate(1925, 1, 1);
      const maxValue = new CalendarDate(2035, 1, 1);
      return { date, minValue, maxValue, args };
    },
    template: `<UiDatePicker
      v-model="date"
      :layout="args.layout"
      :min-value="minValue"
      :max-value="maxValue"
      :placeholder="args.placeholder"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: withMonthYearDropdownsTemplateSource,
      },
    },
  },
};

const withDateRangeTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateValue } from '@internationalized/date'
import { getLocalTimeZone, today } from '@internationalized/date'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const date = ref<DateValue>()
const minValue = today(getLocalTimeZone())
const maxValue = today(getLocalTimeZone()).add({ months: 3 })
</script>

<template>
  <UiDatePicker
    v-model="date"
    :min-value="minValue"
    :max-value="maxValue"
    placeholder="Select appointment"
  />
</template>`;

/**
 * Date picker with min and max date constraints.
 * Only dates within the next 3 months are selectable.
 */
export const WithDateRange: Story = {
  args: {
    placeholder: 'Select appointment',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const date = ref<DateValue>();
      const todayDate = today(getLocalTimeZone());
      const minValue = todayDate;
      const maxValue = todayDate.add({ months: 3 });
      return { date, minValue, maxValue, args };
    },
    template: `<UiDatePicker
      v-model="date"
      :min-value="minValue"
      :max-value="maxValue"
      :placeholder="args.placeholder"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: withDateRangeTemplateSource,
      },
    },
  },
};

const disabledWeekendsTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateValue } from '@internationalized/date'
import { getLocalTimeZone } from '@internationalized/date'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const date = ref<DateValue>()

// Disable weekends (Sunday = 0, Saturday = 6)
const isDateDisabled = (date: DateValue) => {
  const dayOfWeek = date.toDate(getLocalTimeZone()).getDay()
  return dayOfWeek === 0 || dayOfWeek === 6
}
</script>

<template>
  <UiDatePicker
    v-model="date"
    :is-date-disabled="isDateDisabled"
    placeholder="Select weekday"
  />
</template>`;

/**
 * Date picker with weekends disabled.
 * Use the `isDateDisabled` function to disable specific dates based on custom logic.
 */
export const DisabledWeekends: Story = {
  args: {
    placeholder: 'Select weekday',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const date = ref<DateValue>();

      // Disable weekends (Sunday = 0, Saturday = 6 in JavaScript's getDay())
      const isDateDisabled = (d: DateValue) => {
        const dayOfWeek = d.toDate(getLocalTimeZone()).getDay();
        return dayOfWeek === 0 || dayOfWeek === 6;
      };

      return { date, isDateDisabled, args };
    },
    template: `<UiDatePicker
      v-model="date"
      :is-date-disabled="isDateDisabled"
      :placeholder="args.placeholder"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: disabledWeekendsTemplateSource,
      },
    },
  },
};

const germanLocaleTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateValue } from '@internationalized/date'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const date = ref<DateValue>()
</script>

<template>
  <UiDatePicker
    v-model="date"
    locale="de"
    weekday-format="short"
    placeholder="Datum auswählen"
  />
</template>`;

/**
 * Date picker with German locale and week starting on Monday.
 * Demonstrates i18n capabilities.
 */
export const GermanLocale: Story = {
  args: {
    locale: 'de',
    weekdayFormat: 'short',
    placeholder: 'Datum auswählen',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const date = ref<DateValue>();
      return { date, args };
    },
    template: `<UiDatePicker
      v-model="date"
      :locale="args.locale"
      :weekday-format="args.weekdayFormat"
      :placeholder="args.placeholder"
      :disabled="args.disabled"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: germanLocaleTemplateSource,
      },
    },
  },
};

const disabledTemplateSource = `<script setup lang="ts">
import { UiDatePicker } from '@aleph-alpha/ui-library'
</script>

<template>
  <UiDatePicker disabled placeholder="Date picker disabled" />
</template>`;

/**
 * Disabled date picker state.
 * Users cannot interact with the date picker.
 */
export const Disabled: Story = {
  args: {
    disabled: true,
    placeholder: 'Date picker disabled',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      return { args };
    },
    template: `<UiDatePicker
      :disabled="args.disabled"
      :placeholder="args.placeholder"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: disabledTemplateSource,
      },
    },
  },
};

const customWidthTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateValue } from '@internationalized/date'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const date = ref<DateValue>()
</script>

<template>
  <div class="w-[320px]">
    <UiDatePicker v-model="date" class="w-full" />
  </div>
</template>`;

/**
 * Date picker with custom width.
 * The `class` prop overrides the default width (240px for single, 300px for range).
 * Useful for responsive forms and full-width layouts.
 */
export const CustomWidth: Story = {
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const date = ref<DateValue>();
      return { date, args };
    },
    template: `<div class="w-[320px]">
      <UiDatePicker
        v-model="date"
        class="w-full"
        :disabled="args.disabled"
        :locale="args.locale"
      />
    </div>`,
  }),
  parameters: {
    docs: {
      source: {
        code: customWidthTemplateSource,
      },
    },
  },
};

const keepOpenOnSelectTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateValue } from '@internationalized/date'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const date = ref<DateValue>()
</script>

<template>
  <UiDatePicker
    v-model="date"
    :close-on-select="false"
    placeholder="Stays open on select"
  />
</template>`;

/**
 * Date picker that stays open after selecting a date.
 * Useful when users might want to change their selection.
 */
export const KeepOpenOnSelect: Story = {
  args: {
    closeOnSelect: false,
    placeholder: 'Stays open on select',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const date = ref<DateValue>();
      return { date, args };
    },
    template: `<UiDatePicker
      v-model="date"
      :close-on-select="args.closeOnSelect"
      :placeholder="args.placeholder"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: keepOpenOnSelectTemplateSource,
      },
    },
  },
};

const twoMonthsTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateValue } from '@internationalized/date'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const date = ref<DateValue>()
</script>

<template>
  <UiDatePicker
    v-model="date"
    :number-of-months="2"
    placeholder="Select date (2 months view)"
  />
</template>`;

/**
 * Date picker displaying two months side by side.
 * Provides more context for date selection.
 */
export const TwoMonthsView: Story = {
  args: {
    numberOfMonths: 2,
    placeholder: 'Select date (2 months view)',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const date = ref<DateValue>();
      return { date, args };
    },
    template: `<UiDatePicker
      v-model="date"
      :number-of-months="args.numberOfMonths"
      :placeholder="args.placeholder"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: twoMonthsTemplateSource,
      },
    },
  },
};

const formExampleTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateValue } from '@internationalized/date'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const appointmentDate = ref<DateValue>()
</script>

<template>
  <div class="gap-y-2">
    <label class="text-sm font-medium">Appointment Date</label>
    <UiDatePicker
      v-model="appointmentDate"
      placeholder="Select appointment date"
      class="w-full"
      aria-label="Select appointment date"
    />
    <p class="text-xs text-muted-foreground">
      Choose a date for your appointment.
    </p>
  </div>
</template>`;

/**
 * Date picker used in a form context with label and helper text.
 * Demonstrates proper accessibility with aria-label.
 */
export const FormExample: Story = {
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const appointmentDate = ref<DateValue>();
      return { appointmentDate, args };
    },
    template: `<div class="gap-y-2">
      <label class="text-sm font-medium">Appointment Date</label>
      <UiDatePicker
        v-model="appointmentDate"
        placeholder="Select appointment date"
        class="w-full"
        aria-label="Select appointment date"
        :disabled="args.disabled"
        :locale="args.locale"
      />
      <p class="text-xs text-muted-foreground">
        Choose a date for your appointment.
      </p>
    </div>`,
  }),
  parameters: {
    docs: {
      source: {
        code: formExampleTemplateSource,
      },
    },
  },
};

const rangeTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateRange } from '@aleph-alpha/ui-library'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const dateRange = ref<DateRange>()
</script>

<template>
  <UiDatePicker v-model="dateRange" mode="range" />
</template>`;

/**
 * Date picker in range mode for selecting a date range.
 * Click a start date, then click an end date to complete the range.
 */
export const RangeMode: Story = {
  args: {
    mode: 'range',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const dateRange = ref<DateRange>();
      return { dateRange, args };
    },
    template: `<UiDatePicker
      v-model="dateRange"
      mode="range"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: rangeTemplateSource,
      },
    },
  },
};

const rangeTwoMonthsTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateRange } from '@aleph-alpha/ui-library'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const dateRange = ref<DateRange>()
</script>

<template>
  <UiDatePicker
    v-model="dateRange"
    mode="range"
    :number-of-months="2"
    paged-navigation
    placeholder="Select date range"
  />
</template>`;

/**
 * Range date picker with two months displayed side by side.
 * Ideal for selecting longer date ranges with better context.
 * Uses paged navigation to move both months together.
 */
export const RangeTwoMonths: Story = {
  args: {
    mode: 'range',
    numberOfMonths: 2,
    pagedNavigation: true,
    placeholder: 'Select date range',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const dateRange = ref<DateRange>();
      return { dateRange, args };
    },
    template: `<UiDatePicker
      v-model="dateRange"
      mode="range"
      :number-of-months="2"
      paged-navigation
      placeholder="Select date range"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: rangeTwoMonthsTemplateSource,
      },
    },
  },
};

const rangeWithConstraintsTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateRange } from '@aleph-alpha/ui-library'
import { getLocalTimeZone, today } from '@aleph-alpha/ui-library'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const dateRange = ref<DateRange>()
const minValue = today(getLocalTimeZone())
const maxValue = today(getLocalTimeZone()).add({ months: 6 })
</script>

<template>
  <UiDatePicker
    v-model="dateRange"
    mode="range"
    :min-value="minValue"
    :max-value="maxValue"
    placeholder="Select vacation dates"
  />
</template>`;

/**
 * Range date picker with date constraints.
 * Only dates within the next 6 months are selectable.
 * Perfect for vacation planning or booking systems.
 */
export const RangeWithConstraints: Story = {
  args: {
    mode: 'range',
    placeholder: 'Select vacation dates',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const dateRange = ref<DateRange>();
      const todayDate = today(getLocalTimeZone());
      const minValue = todayDate;
      const maxValue = todayDate.add({ months: 6 });
      return { dateRange, minValue, maxValue, args };
    },
    template: `<UiDatePicker
      v-model="dateRange"
      mode="range"
      :min-value="minValue"
      :max-value="maxValue"
      placeholder="Select vacation dates"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: rangeWithConstraintsTemplateSource,
      },
    },
  },
};

const rangePreselectedTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateRange } from '@aleph-alpha/ui-library'
import { getLocalTimeZone, today } from '@aleph-alpha/ui-library'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const todayDate = today(getLocalTimeZone())
const dateRange = ref<DateRange>({
  start: todayDate,
  end: todayDate.add({ days: 7 }),
})
</script>

<template>
  <UiDatePicker v-model="dateRange" mode="range" :number-of-months="2" />
</template>`;

/**
 * Range date picker with a pre-selected 7-day range starting from today.
 * Shows both months for better visualization of the selected range.
 */
export const RangePreselected: Story = {
  args: {
    mode: 'range',
    numberOfMonths: 2,
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const todayDate = today(getLocalTimeZone());
      const dateRange = ref<DateRange>({
        start: todayDate,
        end: todayDate.add({ days: 7 }),
      });
      return { dateRange, args };
    },
    template: `<UiDatePicker
      v-model="dateRange"
      mode="range"
      :number-of-months="2"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: rangePreselectedTemplateSource,
      },
    },
  },
};

const rangeFormExampleTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateRange } from '@aleph-alpha/ui-library'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const travelDates = ref<DateRange>()
</script>

<template>
  <div class="gap-y-2 max-w-sm">
    <label for="travel-dates" class="text-sm font-medium">
      Travel Dates
    </label>
    <UiDatePicker
      id="travel-dates"
      v-model="travelDates"
      mode="range"
      :number-of-months="2"
      placeholder="Select dates"
      aria-label="Select travel dates"
    />
    <p class="text-xs text-muted-foreground">
      Choose your check-in and check-out dates.
    </p>
  </div>
</template>`;

/**
 * Range date picker in a form context for travel booking.
 * Shows how to use range mode with proper labels and helper text.
 */
export const RangeFormExample: Story = {
  args: {
    mode: 'range',
    numberOfMonths: 2,
    placeholder: 'Select dates',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const travelDates = ref<DateRange>();
      return { travelDates, args };
    },
    template: `<div class="gap-y-2 max-w-sm">
      <label for="travel-dates" class="text-sm font-medium">
        Travel Dates
      </label>
      <UiDatePicker
        id="travel-dates"
        v-model="travelDates"
        mode="range"
        :number-of-months="2"
        placeholder="Select dates"
        aria-label="Select travel dates"
        :disabled="args.disabled"
        :locale="args.locale"
      />
      <p class="text-xs text-muted-foreground">
        Choose your check-in and check-out dates.
      </p>
    </div>`,
  }),
  parameters: {
    docs: {
      source: {
        code: rangeFormExampleTemplateSource,
      },
    },
  },
};

const rangeKeepOpenTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import type { DateRange } from '@aleph-alpha/ui-library'
import { UiDatePicker } from '@aleph-alpha/ui-library'

const dateRange = ref<DateRange>()
</script>

<template>
  <UiDatePicker
    v-model="dateRange"
    mode="range"
    :close-on-select="false"
    placeholder="Stays open after selection"
  />
</template>`;

/**
 * Range date picker that stays open after selecting both dates.
 * Useful when users might want to adjust their date range selection.
 */
export const RangeKeepOpen: Story = {
  args: {
    mode: 'range',
    closeOnSelect: false,
    placeholder: 'Stays open after selection',
  },
  render: (args) => ({
    components: { UiDatePicker },
    setup() {
      const dateRange = ref<DateRange>();
      return { dateRange, args };
    },
    template: `<UiDatePicker
      v-model="dateRange"
      mode="range"
      :close-on-select="args.closeOnSelect"
      :placeholder="args.placeholder"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: rangeKeepOpenTemplateSource,
      },
    },
  },
};
