import { StyledToggle } from '@/components/General/Toggle';
import { ArxInputChangeEvent, type StyledInput } from '@components/General/Input';
import { LitElement, html } from 'lit';
import { customElement, state } from 'lit/decorators.js';

import '@components/General/Fieldset';
import '@components/General/Input';
import '@components/General/Select';

interface DateTimeFormatOptions {
  locale: string;
  weekday: 'long' | 'short' | 'narrow' | '';
  year: 'numeric' | '2-digit' | '';
  month: 'numeric' | '2-digit' | 'long' | 'short' | 'narrow' | '';
  day: 'numeric' | '2-digit' | '';
  hour: 'numeric' | '2-digit' | '';
  minute: 'numeric' | '2-digit' | '';
  second: 'numeric' | '2-digit' | '';
  hour12: boolean;
}

const DEFAULT_OPTIONS: DateTimeFormatOptions = {
  locale: 'en-US',
  weekday: 'short',
  year: 'numeric',
  month: 'long',
  day: '2-digit',
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit',
  hour12: true,
};

@customElement('arx-date-time-settings')
export class DateTimeSettings extends LitElement {
  @state()
  private options: DateTimeFormatOptions = { ...DEFAULT_OPTIONS };

  @state()
  private previewDate = new Date();

  override connectedCallback() {
    super.connectedCallback();
    this.loadFromLocalStorage();
    setInterval(() => {
      this.previewDate = new Date();
      this.requestUpdate();
    }, 1000);
  }

  private loadFromLocalStorage() {
    const savedOptions = localStorage.getItem('dateTimeFormatOptions');
    if (savedOptions) {
      try {
        this.options = { ...DEFAULT_OPTIONS, ...JSON.parse(savedOptions) };
      } catch (e) {
        console.error('Failed to parse saved options', e);
        this.options = { ...DEFAULT_OPTIONS };
      }
    }
  }

  private saveToLocalStorage() {
    localStorage.setItem('dateTimeFormatOptions', JSON.stringify(this.options));
    this.dispatchEvent(
      new CustomEvent('settings-changed', {
        bubbles: true,
        composed: true,
        detail: { options: this.options },
      }),
    );
  }

  private handleChange(key: keyof DateTimeFormatOptions, e: Event) {
    let value = e instanceof ArxInputChangeEvent ? e.detail.value : (e.target as HTMLSelectElement).value;
    const target = e.target as StyledInput | HTMLSelectElement | HTMLInputElement | StyledToggle;

    if (key === 'hour12' && target instanceof StyledToggle) value = target.checked.toString();

    this.options = {
      ...this.options,
      [key]: value,
    };

    if (key === 'locale') this.requestUpdate();

    this.saveToLocalStorage();
  }

  private formatWithOption(option: string, type: keyof DateTimeFormatOptions): string {
    if (option === '') return '';
    const date = this.previewDate;
    const locale = this.options.locale;

    const formatterOptions: Intl.DateTimeFormatOptions = {
      [type]: option,
    };

    // Special case for hour to respect hour12 setting
    if (type === 'hour') formatterOptions.hour12 = this.options.hour12;

    try {
      return new Intl.DateTimeFormat(locale, formatterOptions).format(date);
    } catch (e) {
      console.error(`Error formatting with option ${option} for ${type}`, e);
      return 'Error: Invalid format';
    }
  }

  private formatPreview(): string {
    return new Date(this.previewDate).toLocaleString(this.options.locale, {
      weekday: this.options.weekday === '' ? undefined : this.options.weekday,
      year: this.options.year === '' ? undefined : this.options.year,
      month: this.options.month === '' ? undefined : this.options.month,
      day: this.options.day === '' ? undefined : this.options.day,
      hour: this.options.hour === '' ? undefined : this.options.hour,
      minute: this.options.minute === '' ? undefined : this.options.minute,
      second: this.options.second === '' ? undefined : this.options.second,
      hour12: this.options.hour12,
    });
  }

  override render() {
    return html`
      <arx-fieldset legend="Date/Time Settings">
        <arx-input
          label="Locale"
          type="text"
          .value=${this.options.locale}
          @change=${(e: Event) => this.handleChange('locale', e)}
        >
        </arx-input>

        <arx-select
          label="Weekday Format"
          .value=${this.options.weekday}
          @change=${(e: Event) => this.handleChange('weekday', e)}
          .options=${[
            {
              value: 'long',
              label: `Long (${this.formatWithOption('long', 'weekday')})`,
            },
            {
              value: 'short',
              label: `Short (${this.formatWithOption('short', 'weekday')})`,
            },
            {
              value: 'narrow',
              label: `Narrow (${this.formatWithOption('narrow', 'weekday')})`,
            },
          ]}
        ></arx-select>

        <arx-select
          label="Year Format"
          .value=${this.options.year}
          @change=${(e: Event) => this.handleChange('year', e)}
          .options=${[
            {
              value: 'numeric',
              label: `Numeric (${this.formatWithOption('numeric', 'year')})`,
            },
            {
              value: '2-digit',
              label: `2-digit (${this.formatWithOption('2-digit', 'year')})`,
            },
            {
              value: '',
              label: 'None',
            },
          ]}
        ></arx-select>

        <arx-select
          label="Month Format"
          .value=${this.options.month}
          @change=${(e: Event) => this.handleChange('month', e)}
          .options=${[
            {
              value: 'long',
              label: `Long (${this.formatWithOption('long', 'month')})`,
            },
            {
              value: 'short',
              label: `Short (${this.formatWithOption('short', 'month')})`,
            },
            {
              value: 'narrow',
              label: `Narrow (${this.formatWithOption('narrow', 'month')})`,
            },
            {
              value: 'numeric',
              label: `Numeric (${this.formatWithOption('numeric', 'month')})`,
            },
            {
              value: '2-digit',
              label: `2-digit (${this.formatWithOption('2-digit', 'month')})`,
            },
            {
              value: '',
              label: 'None',
            },
          ]}
        ></arx-select>

        <arx-select
          label="Day Format"
          .value=${this.options.day}
          @change=${(e: Event) => this.handleChange('day', e)}
          .options=${[
            {
              value: 'numeric',
              label: `Numeric (${this.formatWithOption('numeric', 'day')})`,
            },
            {
              value: '2-digit',
              label: `2-digit (${this.formatWithOption('2-digit', 'day')})`,
            },
            {
              value: '',
              label: 'None',
            },
          ]}
        ></arx-select>

        <arx-select
          label="Hour Format"
          .value=${this.options.hour}
          @change=${(e: Event) => this.handleChange('hour', e)}
          .options=${[
            {
              value: 'numeric',
              label: 'Numeric',
            },
            {
              value: '2-digit',
              label: '2-digit',
            },
            {
              value: '',
              label: 'None',
            },
          ]}
        ></arx-select>

        <arx-select
          label="Minute Format"
          .value=${this.options.minute}
          @change=${(e: Event) => this.handleChange('minute', e)}
          .options=${[
            {
              value: 'numeric',
              label: 'Numeric',
            },
            {
              value: '2-digit',
              label: '2-digit',
            },
            {
              value: '',
              label: 'None',
            },
          ]}
        ></arx-select>

        <arx-select
          label="Second Format"
          .value=${this.options.second}
          @change=${(e: Event) => this.handleChange('second', e)}
          .options=${[
            {
              value: 'numeric',
              label: 'Numeric',
            },
            {
              value: '2-digit',
              label: '2-digit',
            },
            {
              value: '',
              label: 'None',
            },
          ]}
        ></arx-select>

        <arx-toggle
          label="Use 12-hour format"
          ?checked=${this.options.hour12}
          @change=${(e: Event) => this.handleChange('hour12', e)}
        ></arx-toggle>

        <h3>Preview</h3>
        <p>${this.formatPreview()}</p>
      </arx-fieldset>
    `;
  }
}
