import {
  Component,
  Input,
  OnInit,
  forwardRef,
  inject,
} from '@angular/core';
import {
  ControlValueAccessor,
  FormsModule,
  NG_VALUE_ACCESSOR,
} from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
import { getBrowserTimezone, TimezoneApiService, TimezoneGroup } from '@calendar/core';

@Component({
  selector: 'cal-timezone-select',
  standalone: true,
  imports: [FormsModule, MatFormFieldModule, MatSelectModule],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => TimezoneSelectComponent),
      multi: true,
    },
  ],
  template: `
    @if (compact) {
      <label class="tz-compact">
        <span class="tz-compact-label">{{ label }}</span>
        <select
          class="tz-compact-select"
          [ngModel]="value"
          (ngModelChange)="onSelect($event)"
          (blur)="onTouched()"
          [disabled]="disabled || loading"
        >
          @if (loading) {
            <option value="">Loading timezones…</option>
          }
          @for (group of groups; track group.region) {
            <optgroup [label]="group.region">
              @for (tz of group.timezones; track tz.ianaId) {
                <option [value]="tz.ianaId">{{ tz.label }} ({{ tz.ianaId }})</option>
              }
            </optgroup>
          }
        </select>
        @if (loadError) {
          <span class="tz-compact-error">{{ loadError }}</span>
        }
      </label>
    } @else {
      <mat-form-field appearance="outline" class="timezone-field" subscriptSizing="dynamic">
        <mat-label>{{ label }}</mat-label>
        <mat-select
          [ngModel]="value"
          (ngModelChange)="onSelect($event)"
          (blur)="onTouched()"
          [disabled]="disabled || loading"
          panelClass="timezone-select-panel"
        >
          @for (group of groups; track group.region) {
            <mat-optgroup [label]="group.region">
              @for (tz of group.timezones; track tz.ianaId) {
                <mat-option [value]="tz.ianaId">{{ tz.label }} ({{ tz.ianaId }})</mat-option>
              }
            </mat-optgroup>
          }
        </mat-select>
        @if (loading) {
          <mat-hint>Loading timezones…</mat-hint>
        }
        @if (loadError) {
          <mat-hint class="error-hint">{{ loadError }}</mat-hint>
        }
      </mat-form-field>
    }
  `,
  styles: [
    `
      :host {
        display: block;
        width: 100%;
      }
      .timezone-field {
        width: 100%;
      }
      .error-hint {
        color: var(--cal-danger, #dc2626);
      }
      .tz-compact {
        display: flex;
        flex-direction: column;
        gap: 0.35rem;
        width: 100%;
      }
      .tz-compact-label {
        font-size: 0.8rem;
        font-weight: 600;
        color: #475569;
        line-height: 1.3;
      }
      .tz-compact-select {
        width: 100%;
        box-sizing: border-box;
        min-height: 42px;
        padding: 0.55rem 0.75rem;
        border: 1px solid #cbd5e1;
        border-radius: 10px;
        background: #fff;
        color: #0f172a;
        font: inherit;
        font-size: 0.9rem;
        line-height: 1.35;
      }
      .tz-compact-select:focus {
        outline: 2px solid #818cf8;
        outline-offset: 1px;
        border-color: #6366f1;
      }
      .tz-compact-select:disabled {
        background: #f8fafc;
        color: #94a3b8;
      }
      .tz-compact-error {
        font-size: 0.75rem;
        color: var(--cal-danger, #dc2626);
      }
    `,
  ],
})
export class TimezoneSelectComponent implements ControlValueAccessor, OnInit {
  private timezoneApi = inject(TimezoneApiService);

  @Input() label = 'Timezone';
  /** Preferred IANA id when the current value is missing/unsupported (e.g. host event TZ). */
  @Input() preferredTimezone: string | null = null;
  /** Native select — avoids Material overlay collisions in embed iframes. */
  @Input() compact = false;

  groups: TimezoneGroup[] = [];
  value = '';
  disabled = false;
  loading = true;
  loadError: string | null = null;

  onChange: (value: string) => void = () => {};
  onTouched: () => void = () => {};

  ngOnInit(): void {
    this.timezoneApi.list().subscribe({
      next: (res) => {
        this.groups = res.groups;
        this.loading = false;
        const supported = new Set(res.data.map((tz) => tz.ianaId));
        if (!this.value || !supported.has(this.value)) {
          const browserTz = getBrowserTimezone();
          const preferred =
            (this.preferredTimezone && supported.has(this.preferredTimezone)
              ? this.preferredTimezone
              : null) ||
            (supported.has(browserTz) ? browserTz : null) ||
            'UTC';
          this.onSelect(preferred);
        }
      },
      error: () => {
        this.loading = false;
        this.loadError = 'Could not load timezones. Check that the API is running.';
      },
    });
  }

  writeValue(value: string | null): void {
    this.value = value ?? '';
  }

  registerOnChange(fn: (value: string) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  onSelect(value: string): void {
    this.value = value;
    this.onChange(value);
  }
}
