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

/**
 * UiRangeCalendar is a month-grid date picker for selecting a start and end date.
 * Use it standalone or inside a `UiPopover` to power range filters and reservation flows; for single-date selection, use `UiCalendar`.
 */
const meta: Meta<typeof UiRangeCalendar> = {
  title: 'Components/UiRangeCalendar',
  component: UiRangeCalendar,
  tags: ['autodocs'],
  decorators: [
    () => ({
      template: '<div class="inline-block"><story /></div>',
    }),
  ],
  argTypes: {
    disabled: {
      control: 'boolean',
      description: 'Whether the calendar is disabled.',
    },
    readonly: {
      control: 'boolean',
      description:
        'Whether the calendar is read-only. Users can navigate but not select dates.',
    },
    locale: {
      control: 'select',
      options: ['en', 'de', 'fr', 'es', 'pl'],
      description: 'The locale to use for formatting dates and weekday names.',
    },
    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.',
    },
    weekdayFormat: {
      control: 'select',
      options: ['narrow', 'short', 'long'],
      description:
        'The format to use for weekday labels. Note: "long" is not recommended as full weekday names do not fit well.',
    },
    fixedWeeks: {
      control: 'boolean',
      description: 'Whether to always show 6 weeks in the calendar.',
    },
    preventDeselect: {
      control: 'boolean',
      description: 'Whether to prevent deselecting a date.',
    },
    calendarLabel: {
      control: 'text',
      description: 'The accessible label for the calendar.',
    },
    initialFocus: {
      control: 'boolean',
      description: 'If true, focuses the calendar on mount.',
    },
  },
  args: {
    disabled: false,
    readonly: false,
    locale: 'en',
    weekStartsOn: 0,
    numberOfMonths: 1,
    pagedNavigation: false,
    weekdayFormat: 'narrow',
    fixedWeeks: false,
    preventDeselect: false,
    initialFocus: false,
  },
};

export default meta;

type Story = StoryObj<typeof UiRangeCalendar>;

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

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

<template>
  <UiRangeCalendar v-model="dateRange" />
</template>`;

/**
 * Basic range calendar for selecting a date range.
 * Click on a start date, then click on an end date to select a range.
 * Use the Controls panel to explore all available props.
 */
export const Default: Story = {
  render: (args) => ({
    components: { UiRangeCalendar },
    setup() {
      const dateRange = ref<DateRange>();
      const placeholder = ref(today(getLocalTimeZone()));
      return { dateRange, placeholder, args };
    },
    template: `<UiRangeCalendar
      v-model="dateRange"
      :default-placeholder="placeholder"
      :disabled="args.disabled"
      :readonly="args.readonly"
      :locale="args.locale"
      :week-starts-on="args.weekStartsOn"
      :number-of-months="args.numberOfMonths"
      :paged-navigation="args.pagedNavigation"
      :weekday-format="args.weekdayFormat"
      :fixed-weeks="args.fixedWeeks"
      :prevent-deselect="args.preventDeselect"
      :calendar-label="args.calendarLabel"
      :initial-focus="args.initialFocus"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: defaultTemplateSource,
      },
    },
  },
};

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

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

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

/**
 * Range calendar displaying two months side by side.
 * This is the recommended layout for date range selection as it provides
 * better context when selecting ranges that span multiple months.
 */
export const TwoMonths: Story = {
  args: {
    numberOfMonths: 2,
  },
  render: (args) => ({
    components: { UiRangeCalendar },
    setup() {
      const dateRange = ref<DateRange>();
      const placeholder = ref(today(getLocalTimeZone()));
      return { dateRange, placeholder, args };
    },
    template: `<UiRangeCalendar
      v-model="dateRange"
      :default-placeholder="placeholder"
      :number-of-months="args.numberOfMonths"
      :paged-navigation="args.pagedNavigation"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: multipleMonthsTemplateSource,
      },
    },
  },
};

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

const dateRange = ref<DateRange>({
  start: new CalendarDate(2025, 1, 10),
  end: new CalendarDate(2025, 1, 20),
})
</script>

<template>
  <UiRangeCalendar v-model="dateRange" />
</template>`;

/**
 * Range calendar with a pre-selected date range.
 * Useful for editing existing date ranges or showing defaults.
 */
export const WithPreselectedRange: Story = {
  render: (args) => ({
    components: { UiRangeCalendar },
    setup() {
      const dateRange = ref<DateRange>({
        start: new CalendarDate(2025, 1, 10),
        end: new CalendarDate(2025, 1, 20),
      });
      const placeholder = ref(new CalendarDate(2025, 1, 1));
      return { dateRange, placeholder, args };
    },
    template: `<UiRangeCalendar
      v-model="dateRange"
      :default-placeholder="placeholder"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: withPreselectedRangeTemplateSource,
      },
    },
  },
};

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

const dateRange = ref<DateRange>()

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

<template>
  <UiRangeCalendar v-model="dateRange" :is-date-disabled="isDateDisabled" />
</template>`;

/**
 * Range calendar with weekends disabled.
 * Use the `isDateDisabled` function to disable specific dates.
 * Useful for business date selection.
 */
export const DisabledWeekends: Story = {
  render: (args) => ({
    components: { UiRangeCalendar },
    setup() {
      const dateRange = ref<DateRange>();
      const placeholder = ref(today(getLocalTimeZone()));

      const isDateDisabled = (d: DateValue) => {
        const dayOfWeek = d.toDate(getLocalTimeZone()).getDay();
        return dayOfWeek === 0 || dayOfWeek === 6;
      };

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

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

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

<template>
  <UiRangeCalendar v-model="dateRange" :min-value="minValue" :max-value="maxValue" />
</template>`;

/**
 * Range calendar with min and max date constraints.
 * Only dates within the next 3 months are selectable.
 */
export const WithDateConstraints: Story = {
  render: (args) => ({
    components: { UiRangeCalendar },
    setup() {
      const dateRange = ref<DateRange>();
      const todayDate = today(getLocalTimeZone());
      const minValue = todayDate;
      const maxValue = todayDate.add({ months: 3 });

      return { dateRange, minValue, maxValue, args };
    },
    template: `<UiRangeCalendar
      v-model="dateRange"
      :min-value="minValue"
      :max-value="maxValue"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: dateRangeConstraintsTemplateSource,
      },
    },
  },
};

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

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

<template>
  <UiRangeCalendar v-model="dateRange" locale="de" weekday-format="short" />
</template>`;

/**
 * Range calendar with German locale and week starting on Monday.
 * Demonstrates i18n capabilities.
 */
export const GermanLocale: Story = {
  args: {
    locale: 'de',
    weekdayFormat: 'short',
  },
  render: (args) => ({
    components: { UiRangeCalendar },
    setup() {
      const dateRange = ref<DateRange>();
      const placeholder = ref(today(getLocalTimeZone()));
      return { dateRange, placeholder, args };
    },
    template: `<UiRangeCalendar
      v-model="dateRange"
      :default-placeholder="placeholder"
      :locale="args.locale"
      :weekday-format="args.weekdayFormat"
      :disabled="args.disabled"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: germanLocaleTemplateSource,
      },
    },
  },
};

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

<template>
  <UiRangeCalendar disabled />
</template>`;

/**
 * Disabled range calendar state.
 * Users cannot interact with the calendar.
 */
export const Disabled: Story = {
  args: {
    disabled: true,
  },
  render: (args) => ({
    components: { UiRangeCalendar },
    setup() {
      const placeholder = ref(today(getLocalTimeZone()));
      return { placeholder, args };
    },
    template: `<UiRangeCalendar
      :default-placeholder="placeholder"
      :disabled="args.disabled"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: disabledTemplateSource,
      },
    },
  },
};

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

const dateRange = ref<DateRange>({
  start: new CalendarDate(2025, 1, 10),
  end: new CalendarDate(2025, 1, 20),
})
</script>

<template>
  <UiRangeCalendar v-model="dateRange" readonly />
</template>`;

/**
 * Read-only range calendar state.
 * Users can navigate between months but cannot select dates.
 */
export const Readonly: Story = {
  args: {
    readonly: true,
  },
  render: (args) => ({
    components: { UiRangeCalendar },
    setup() {
      const dateRange = ref<DateRange>({
        start: new CalendarDate(2025, 1, 10),
        end: new CalendarDate(2025, 1, 20),
      });
      const placeholder = ref(new CalendarDate(2025, 1, 1));
      return { dateRange, placeholder, args };
    },
    template: `<UiRangeCalendar
      v-model="dateRange"
      :default-placeholder="placeholder"
      :readonly="args.readonly"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: readonlyTemplateSource,
      },
    },
  },
};

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

const dateRange = ref<DateRange>()

// Mark certain dates as unavailable (e.g., holidays)
const isDateUnavailable = (date: DateValue) => {
  return date.day === 15 || date.day === 25
}
</script>

<template>
  <UiRangeCalendar v-model="dateRange" :is-date-unavailable="isDateUnavailable" />
</template>`;

/**
 * Range calendar with unavailable dates marked.
 * Unavailable dates are styled differently (strikethrough) but may still be selectable.
 * Use this for holidays or dates with limited availability.
 */
export const UnavailableDates: Story = {
  render: (args) => ({
    components: { UiRangeCalendar },
    setup() {
      const dateRange = ref<DateRange>();
      const placeholder = ref(today(getLocalTimeZone()));

      const isDateUnavailable = (d: DateValue) => {
        return d.day === 15 || d.day === 25;
      };

      return { dateRange, placeholder, isDateUnavailable, args };
    },
    template: `<UiRangeCalendar
      v-model="dateRange"
      :default-placeholder="placeholder"
      :is-date-unavailable="isDateUnavailable"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: unavailableDatesTemplateSource,
      },
    },
  },
};

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

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

<template>
  <UiRangeCalendar v-model="dateRange" fixed-weeks />
</template>`;

/**
 * Range calendar that always shows 6 weeks.
 * Useful for maintaining consistent height regardless of the month.
 */
export const FixedWeeks: Story = {
  args: {
    fixedWeeks: true,
  },
  render: (args) => ({
    components: { UiRangeCalendar },
    setup() {
      const dateRange = ref<DateRange>();
      const placeholder = ref(today(getLocalTimeZone()));
      return { dateRange, placeholder, args };
    },
    template: `<UiRangeCalendar
      v-model="dateRange"
      :default-placeholder="placeholder"
      :fixed-weeks="args.fixedWeeks"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: fixedWeeksTemplateSource,
      },
    },
  },
};

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

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

<template>
  <UiRangeCalendar v-model="dateRange" :number-of-months="2" paged-navigation />
</template>`;

/**
 * Range calendar with paged navigation.
 * When enabled with multiple months, the prev/next buttons navigate
 * by the full number of visible months instead of one month at a time.
 */
export const PagedNavigation: Story = {
  args: {
    numberOfMonths: 2,
    pagedNavigation: true,
  },
  render: (args) => ({
    components: { UiRangeCalendar },
    setup() {
      const dateRange = ref<DateRange>();
      const placeholder = ref(today(getLocalTimeZone()));
      return { dateRange, placeholder, args };
    },
    template: `<UiRangeCalendar
      v-model="dateRange"
      :default-placeholder="placeholder"
      :number-of-months="args.numberOfMonths"
      :paged-navigation="args.pagedNavigation"
      :disabled="args.disabled"
      :locale="args.locale"
    />`,
  }),
  parameters: {
    docs: {
      source: {
        code: pagedNavigationTemplateSource,
      },
    },
  },
};
