import { CommonModule } from '@angular/common';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { provideAnimations } from '@angular/platform-browser/animations';
import {
  applicationConfig,
  argsToTemplate,
  componentWrapperDecorator,
  Meta,
  moduleMetadata,
  StoryObj
} from '@storybook/angular';
import { dataCountries } from '@tools/storybook';
import { AutocompleteComponent, ButtonComponent, HighlightDirective, IconComponent } from '../../public-api';

/**
 * `<nj-autocomplete>` is compatible with `@angular/forms` and supports both `FormsModule` and `ReactiveFormsModule`.
 * It also extends `FormItem` so it can take all its props
 */
const meta: Meta<AutocompleteComponent> = {
  title: 'Components/Autocomplete',
  id: 'autocomplete',
  component: AutocompleteComponent,
  decorators: [
    moduleMetadata({
      imports: [IconComponent, HighlightDirective, CommonModule, FormsModule, ReactiveFormsModule, ButtonComponent]
    }),
    applicationConfig({
      providers: [provideAnimations()]
    }),
    componentWrapperDecorator(
      (story) => `
        <div style="height: 300px">${story}</div>
    `
    )
  ],
  parameters: {
    docs: {
      imports: [AutocompleteComponent, HighlightDirective],
      controls: {
        exclude: new RegExp(/password\w*/)
      }
    }
  },
  argTypes: {
    data: {
      control: {
        type: null
      }
    },
    search: {
      control: {
        type: null
      }
    },
    iconClick: {
      control: {
        type: null
      }
    },
    iconKeydown: {
      control: {
        type: null
      }
    },
    wrapperClick: {
      control: {
        type: null
      }
    }
  }
};
export default meta;

type AutocompleteWithLabelAndSubscriptProps = AutocompleteComponent & {
  label?: string;
  subscript?: string;
};
type Story = StoryObj<AutocompleteWithLabelAndSubscriptProps>;

export const Autocomplete: Story = {
  args: {
    label: 'Label',
    subscript: 'Hint to help the user fill the input',
    inputId: 'inputId',
    data: dataCountries,
    listLabel: 'Countries suggestions',
    inputInstructions:
      'Use the UP / DOWN arrows to navigate within the suggestion list. Press Enter to select an option. On touch devices, use swipe to navigate and double tap to select an option'
  },
  render: (args) => ({
    props: args,
    template: `
    <nj-autocomplete ${argsToTemplate(args, { exclude: ['label', 'subscript'] })}>
      <span njFormLabel>{{label}}</span>
      <span njFormSubscript>{{subscript}}</span>
    </nj-autocomplete>
    `
  })
};

export const AutocompleteWithAdditionalContent: Story = {
  args: {
    label: 'Label',
    subscript: 'Hint to help the user fill the input',
    inputId: 'additional',
    data: dataCountries,
    inputInstructions:
      'Use the UP / DOWN arrows to navigate within the suggestion list. Press Enter to select an option. On touch devices, use swipe to navigate and double tap to select an option'
  },
  render: (args) => ({
    props: args,
    template: `
      <nj-autocomplete ${argsToTemplate(args, { exclude: ['label', 'subscript'] })} #autocomplete>
        <span njFormLabel>{{label}}</span>
        <span njFormSubscript>{{subscript}}</span>
        <!--Example of additional content on top of list item-->
        <div
          njAutocompleteAdditional
          *ngIf="autocomplete.searchText as searchText"
          style="padding: 16px 14px; display: flex; align-items: center; justify-content: space-between"
        >
          <span>Add country "{{searchText}}"</span>
          <nj-button size="small" (click)="$event.preventDefault()">
            Add
          </nj-button>
        </div>
      </nj-autocomplete>
  `
  })
};

export const AutocompleteAppend: Story = {
  args: {
    label: 'Label',
    subscript: 'Hint to help the user fill the input',
    inputId: 'append',
    data: dataCountries,
    inputInstructions:
      'Use the UP / DOWN arrows to navigate within the suggestion list. Press Enter to select an option. On touch devices, use swipe to navigate and double tap to select an option'
  },
  render: (args) => ({
    props: args,
    template: `
      <nj-autocomplete ${argsToTemplate(args, { exclude: ['label', 'subscript'] })} #autocomplete>
        <span njFormLabel>{{label}}</span>
        <span njFormSubscript>{{subscript}}</span>
      </nj-autocomplete>
  `
  })
};

export const AutocompleteWithCustomTemplates: Story = {
  args: {
    label: 'Label',
    subscript: 'Hint to help the user fill the input',
    inputId: 'customTemplate',
    data: dataCountries,
    inputInstructions:
      'Use the UP / DOWN arrows to navigate within the suggestion list. Press Enter to select an option. On touch devices, use swipe to navigate and double tap to select an option'
  },
  render: (args) => ({
    props: args,
    template: `
      <nj-autocomplete ${argsToTemplate(args, { exclude: ['label', 'subscript'] })} #autocomplete>
        <span njFormLabel>{{label}}</span>
        <span njFormSubscript>{{subscript}}</span>

        <!--Example of custom labels-->
        <ng-template #njAutocompleteOptionLabel let-option="option">
          <div style="display:flex; align-items: center; gap: 8px">
            <img
              style="width: 20px; height: 16px"
              [src]="'https://flagsapi.com/' + option?.value + '/flat/24.png'"
            />
            <span
              njHighlight
              [content]="option?.label"
              [textToHighlight]="autocomplete.searchText"
            ></span>
          </div>
        </ng-template>

        <!--Example of custom number of results text-->
        <ng-template
          #njAutocompleteSearchResults
          let-numberOfFilteredData="numberOfFilteredData"
        >
          <div
            class="nj-form-item__list-item-hint"
            style="display:flex; align-items: center; gap: 8px"
            aria-hidden="true"
          >
            <nj-icon name="flag"></nj-icon>
            <span>
              {{numberOfFilteredData}} {{autocomplete.resultsNumberMessage}}
            </span>
          </div>
        </ng-template>

        <!--Example of custom no result text-->
        <ng-template #njAutocompleteNoResult>
          <p class="nj-form-item__list-item-hint">
            Custom no results for "{{autocomplete.searchText}}"
          </p>
        </ng-template>
      </nj-autocomplete>
  `
  })
};

/**
 * `AutocompleteComponent` implements `ControlValueAccessor` interface.
 * It can be interfaced with `FormsModule` and `ReactiveFormsModule` APIs
 */
export const WithAngularFormsAPI: Story = {
  name: 'Use core Angular forms APIs',
  args: {
    label: 'Label',
    subscript: 'Hint to help the user fill the input',
    inputId: 'inputId',
    data: dataCountries,
    listLabel: 'Countries suggestions',
    inputInstructions:
      'Use the UP / DOWN arrows to navigate within the suggestion list. Press Enter to select an option. On touch devices, use swipe to navigate and double tap to select an option'
  },
  render: (args) => ({
    props: {
      ...args,
      value: null,
      autocompleteControl: new FormControl(),
      formControlState() {
        const { pristine, dirty, touched, untouched, value, status, errors } = this.autocompleteControl;
        return { pristine, dirty, touched, untouched, value, status, errors };
      }
    },
    template: `
    <h3>With ngModel - FormsModule</h3>
    <p>
      <nj-autocomplete [(ngModel)]="value" ${argsToTemplate(args, { exclude: ['label', 'subscript'] })}>
        <span njFormLabel>{{label}}</span>
        <span njFormSubscript>{{subscript}}</span>
      </nj-autocomplete>
    </p>
    <pre>Value: {{ value | json }}</pre>
    <hr>
    <h3>With FormControl - ReactiveFormsModule</h3>
    <p>
      <nj-autocomplete [formControl]="autocompleteControl" ${argsToTemplate(args, { exclude: ['label', 'subscript'] })}>
        <span njFormLabel>{{label}}</span>
        <span njFormSubscript>{{subscript}}</span>
      </nj-autocomplete>
    </p>
    <pre>Control: {{ formControlState() | json }}</pre>
    `
  })
};
