import { Component, inject } from '@angular/core'
import {
  AbstractControl,
  FormControl,
  FormGroup,
  ReactiveFormsModule,
  Validators,
} from '@angular/forms'
import { Router } from '@angular/router'
import {
  ErrorService,
  i18nPipe,
  normalizeHostname,
  randomServerName,
  serverNameValidator,
} from '@start9labs/shared'
import { TuiAutoFocus, TuiMapperPipe, TuiValidator } from '@taiga-ui/cdk'
import {
  TuiButton,
  TuiError,
  TuiIcon,
  TuiInput,
  TuiTitle,
  tuiValidationErrorsProvider,
} from '@taiga-ui/core'
import { TuiNotificationMiddleService, TuiPassword } from '@taiga-ui/kit'
import { TuiCardLarge, TuiForm, TuiHeader } from '@taiga-ui/layout'
import { StateService } from '../services/state.service'

@Component({
  template: `
    <form
      tuiCardLarge="compact"
      tuiForm
      [formGroup]="form"
      (ngSubmit)="submit()"
    >
      <header tuiHeader>
        <h2 tuiTitle>
          {{
            isFresh
              ? ('Set Up Your Server' | i18n)
              : ('Set New Password (Optional)' | i18n)
          }}
        </h2>
      </header>

      @if (isFresh) {
        <tui-textfield>
          <label tuiLabel>{{ 'Server Name' | i18n }}</label>
          <input tuiInput formControlName="name" />
          <button
            tuiIconButton
            type="button"
            appearance="icon"
            iconStart="@tui.refresh-cw"
            (click)="randomizeName()"
          ></button>
        </tui-textfield>
        <tui-error formControlName="name" />
        @if (form.controls.name.value?.trim() && !form.controls.name.errors) {
          <tui-error class="g-secondary" error="{{ derivedHostname }}.local" />
        }
      }

      <tui-textfield>
        <label tuiLabel>
          {{ isFresh ? ('Password' | i18n) : ('New Password' | i18n) }}
        </label>
        <input
          tuiInput
          type="password"
          [tuiAutoFocus]="!isFresh"
          maxlength="64"
          formControlName="password"
        />
        <tui-icon tuiPassword />
      </tui-textfield>
      <tui-error formControlName="password" />

      <tui-textfield>
        <label tuiLabel>{{ 'Confirm Password' | i18n }}</label>
        <input
          tuiInput
          type="password"
          formControlName="confirm"
          [tuiValidator]="
            form.controls.password.value || '' | tuiMapper: validator
          "
        />
        <tui-icon tuiPassword />
      </tui-textfield>
      <tui-error formControlName="confirm" />

      <footer>
        @if (!isFresh) {
          <button
            tuiButton
            size="m"
            appearance="secondary"
            type="button"
            (click)="skip()"
          >
            {{ 'Skip' | i18n }}
          </button>
        }
        <button tuiButton size="m" [disabled]="form.invalid">
          {{ 'Finish' | i18n }}
        </button>
      </footer>
    </form>
  `,
  imports: [
    ReactiveFormsModule,
    TuiCardLarge,
    TuiButton,
    TuiError,
    TuiAutoFocus,
    TuiInput,
    TuiForm,
    TuiPassword,
    TuiValidator,
    TuiIcon,
    TuiMapperPipe,
    TuiHeader,
    TuiTitle,
    i18nPipe,
  ],
  providers: [
    tuiValidationErrorsProvider({
      required: 'Required',
      minlength: 'Must be 12 characters or greater',
      maxlength: 'Must be 64 character or less',
      match: 'Passwords do not match',
      hostnameMinLength: 'Hostname must be at least 4 characters',
      hostnameMaxLength: 'Hostname must be 63 characters or less',
    }),
  ],
})
export default class PasswordPage {
  private readonly router = inject(Router)
  private readonly loader = inject(TuiNotificationMiddleService)
  private readonly errorService = inject(ErrorService)
  private readonly stateService = inject(StateService)
  private readonly i18n = inject(i18nPipe)

  // Fresh install requires password and name
  readonly isFresh = this.stateService.setupType === 'fresh'

  readonly form = new FormGroup({
    password: new FormControl('', [
      ...(this.isFresh ? [Validators.required] : []),
      Validators.minLength(12),
      Validators.maxLength(64),
    ]),
    confirm: new FormControl(''),
    name: new FormControl(
      this.isFresh ? randomServerName() : '',
      this.isFresh ? [Validators.required, serverNameValidator] : [],
    ),
  })

  readonly validator = (value: string) => (control: AbstractControl) =>
    value === control.value
      ? null
      : { match: this.i18n.transform('Passwords do not match') }

  randomizeName() {
    this.form.controls.name.setValue(randomServerName())
  }

  get derivedHostname(): string {
    return normalizeHostname(this.form.controls.name.value || '')
  }

  async skip() {
    // Skip means no new password - pass null
    await this.executeSetup(null)
  }

  async submit() {
    await this.executeSetup(this.form.controls.password.value)
  }

  private async executeSetup(password: string | null) {
    const loader = this.loader.open('Starting setup').subscribe()
    const name = this.form.controls.name.value || ''
    const hostname = normalizeHostname(name)

    try {
      if (this.stateService.setupType === 'attach') {
        await this.stateService.attachDrive(password)
      } else {
        // fresh, restore, or transfer - all use execute
        await this.stateService.executeSetup(password, name, hostname)
      }

      await this.router.navigate(['/loading'])
    } catch (e: any) {
      this.errorService.handleError(e)
    } finally {
      loader.unsubscribe()
    }
  }
}
