import * as React from "react";
import * as lodash from "lodash";
import IJitzSPContext from "../data/interfaces/IJitzSPContext";
import UtilityService from "../services/UtilityService";
import {
  CompactPeoplePicker,
  IBasePickerSuggestionsProps,
  IContextualMenuItem,
  IPersonaProps,
  NormalPeoplePicker,
} from "@fluentui/react";
import {
  IClientPeoplePickerSearchUser,
  IEnsurableSharePointUser,
  IEnsureUser,
  IJitzPeoplePickerState,
  SharePointUserPersona,
} from "../common/IObjects";

const suggestionProps: IBasePickerSuggestionsProps = {
  suggestionsHeaderText: "Suggested People",
  noResultsFoundText: "No results found",
  loadingText: "Loading",
};

export interface IJitzPeoplePickerProps {
  description: string;
  context: IJitzSPContext;
  hostSiteUrl?: string;
  typePicker: string;
  disabled: boolean;
  principalTypeUser: boolean;
  principalTypeSharePointGroup: boolean;
  principalTypeSecurityGroup: boolean;
  principalTypeDistributionList: boolean;
  numberOfItems: number;
  onChange?: (items: SharePointUserPersona[]) => void;
  prePopulatedItems: string[];
  errorMessage?: string;
  errorCss?: string;
  multiSelect: boolean;
  placeholderText?: string;
  shouldKeepItems?: boolean;
}

export class JitzPeoplePicker extends React.Component<
  IJitzPeoplePickerProps,
  IJitzPeoplePickerState
> {
  private _peopleList: any;
  private contextualMenuItems: IContextualMenuItem[] = [
    {
      key: "newItem",
      icon: "circlePlus",
      name: "New",
    },
    {
      key: "upload",
      icon: "upload",
      name: "Upload",
    },
    {
      key: "divider_1",
      name: "-",
    },
    {
      key: "rename",
      name: "Rename",
    },
    {
      key: "properties",
      name: "Properties",
    },
    {
      key: "disabled",
      name: "Disabled item",
      disabled: true,
    },
  ];
  constructor(props: IJitzPeoplePickerProps) {
    super(props);
    this._peopleList = [];

    this.state = {
      currentPicker: 1,
      disabled: false,
      delayResults: false,
      selectedItems: [],
    };
  }

  public getSelectedItems() {}

  public componentDidMount(): void {
    this.setState({ disabled: this.props.disabled });
    this.prePopulate(this.props.prePopulatedItems);
  }

  public componentDidUpdate(
    prevProps: IJitzPeoplePickerProps,
    prevState: IJitzPeoplePickerState,
    prevContext: any
  ): void {
    //this.prePopulate();
  }

  public componentWillReceiveProps(nextProps: IJitzPeoplePickerProps) {
    this.setState({ disabled: nextProps.disabled });
    this.prePopulate(nextProps.prePopulatedItems);
  }

  public render(): React.ReactElement<IJitzPeoplePickerProps> {
    if (this.props.typePicker == "Normal") {
      return (
        <NormalPeoplePicker
          onChange={this._onChange.bind(this)}
          disabled={this.state.disabled}
          inputProps={{ placeholder: this.props.placeholderText || "" }}
          onResolveSuggestions={this._onFilterChanged}
          getTextFromItem={(persona: IPersonaProps) =>
            persona.primaryText || ""
          }
          pickerSuggestionsProps={suggestionProps}
          selectedItems={this.state.selectedItems}
          className={
            "ms-PeoplePicker " +
            (this.props.errorMessage != null &&
            this.props.errorMessage != undefined &&
            this.props.errorMessage.length > 0
              ? this.props.errorCss
              : "")
          }
          key={"normal"}
        />
      );
    } else {
      return (
        <CompactPeoplePicker
          onChange={this._onChange.bind(this)}
          onResolveSuggestions={this._onFilterChanged}
          disabled={this.state.disabled}
          inputProps={{ placeholder: this.props.placeholderText || "" }}
          getTextFromItem={(persona: IPersonaProps) =>
            persona.primaryText || ""
          }
          pickerSuggestionsProps={suggestionProps}
          selectedItems={this.state.selectedItems}
          className={
            "ms-PeoplePicker" +
            (this.props.errorMessage != null &&
            this.props.errorMessage != undefined &&
            this.props.errorMessage.length > 0
              ? this.props.errorCss
              : "")
          }
          key={"normal"}
        />
      );
    }
  }

  private _onChange(items?: any[]) {
    if (
      this.props.shouldKeepItems == undefined ||
      this.props.shouldKeepItems == true
    )
      this.setState({
        selectedItems:
          (this.props.multiSelect
            ? items
            : items != undefined
            ? items.length > 0
              ? [items[0]]
              : items
            : []) || [],
      });

    if (items != undefined) {
      items.map((p, v) => {
        // console.log(p);
        const ensureUserUrl = `${this.props.context.siteUrl}/_api/web/ensureUser`;

        this.props.context.client
          .post(ensureUserUrl, { logonName: p.User.Key })
          .then((response: any) => {
            var res = response.data.d;
            return res;
          })
          .then((res: any) => {});
      });
    }

    if (this.props.onChange) {
      this.props.onChange(items || []);
    }
  }

  private prePopulate = (nextPrePopulatedItems: string[]) => {
    const ensureUserUrl = `${this.props.context.siteUrl}/_api/web/ensureUser`;
    if (
      nextPrePopulatedItems != undefined &&
      nextPrePopulatedItems != null &&
      nextPrePopulatedItems[0] != null
    ) {
      nextPrePopulatedItems.map((item) => {
        // console.log(item);
        this.props.context.client
          .post(ensureUserUrl, { logonName: item })
          .then((response: any) => {
            var res = response.data.d;
            return res;
          })
          .then((res: any) => {
            var pers = new SharePointUserPersona(
              res as IEnsurableSharePointUser
            );
            pers.imageUrl = UtilityService.getProfilePictureUrl(
              this.props.hostSiteUrl || this.props.context.siteUrl,
              pers.User.Email || "",
              "1"
            );
            // (this.props.hostSiteUrl || this.props.context.siteUrl) +
            // `/_layouts/15/userphoto.aspx?size=S&accountname=${pers.User.Email}`;
            var prepopulatedItems = this.state.selectedItems;
            if (
              prepopulatedItems.filter(
                (x: any) => x.User.LoginName == pers.User.LoginName
              ).length == 0
            ) {
              prepopulatedItems.push(pers);
              this.setState({
                selectedItems: this.props.multiSelect
                  ? prepopulatedItems
                  : prepopulatedItems.length > 0
                  ? [prepopulatedItems[0]]
                  : prepopulatedItems,
              });
            }
            if (this.props.onChange) {
              this.props.onChange(prepopulatedItems);
            }
          });
      });
    }
  };

  private _onFilterChanged = (
    filterText: string,
    currentPersonas?: IPersonaProps[]
  ): any => {
    if (filterText) {
      if (filterText.length > 2) {
        return this._searchPeople(filterText, this._peopleList);
      }
    } else {
      return [];
    }
  };

  /**
   * @function
   * Returns fake people results for the Mock mode
   */
  private searchPeopleFromMock(): IPersonaProps[] {
    return (this._peopleList = []);
  }

  /**
   * @function
   * Returns people results after a REST API call
   */
  private _searchPeople(
    terms: string,
    results: IPersonaProps[]
  ): IPersonaProps[] | Promise<IPersonaProps[]> {
    const userRequestUrl: string = `${this.props.context.siteUrl}/_api/SP.UI.ApplicationPages.ClientPeoplePickerWebServiceInterface.clientPeoplePickerSearchUser`;
    let principalType: number = 0;
    if (this.props.principalTypeUser === true) {
      principalType += 1;
    }
    if (this.props.principalTypeSharePointGroup === true) {
      principalType += 8;
    }
    if (this.props.principalTypeSecurityGroup === true) {
      principalType += 4;
    }
    if (this.props.principalTypeDistributionList === true) {
      principalType += 2;
    }
    const userQueryParams = {
      queryParams: {
        AllowEmailAddresses: true,
        AllowMultipleEntities: false,
        AllUrlZones: false,
        MaximumEntitySuggestions: this.props.numberOfItems,
        PrincipalSource: 15,
        // PrincipalType controls the type of entities that are returned in the results.
        // Choices are All - 15, Distribution List - 2 , Security Groups - 4, SharePoint Groups - 8, User - 1.
        // These values can be combined (example: 13 is security + SP groups + users)
        PrincipalType: principalType,
        QueryString: terms,
      },
    };

    return new Promise<SharePointUserPersona[]>((resolve: any, reject: any) =>
      this.props.context.client
        .post(userRequestUrl, userQueryParams)
        .then((response: any) => {
          return response.data.d;
        })
        .then((response: { ClientPeoplePickerSearchUser: string }) => {
          let userQueryResults: IClientPeoplePickerSearchUser[] = JSON.parse(
            response.ClientPeoplePickerSearchUser
          );
          let persons = userQueryResults.map(
            (p) => new SharePointUserPersona(p as IEnsurableSharePointUser)
          );
          persons.map((p, index) => {
            persons[index].imageUrl = UtilityService.getProfilePictureUrl(
              this.props.hostSiteUrl || this.props.context.siteUrl,
              persons[index].User.Email ||
                persons[index].User.Key.substr(
                  persons[index].User.Key.lastIndexOf("|") + 1
                ),
              "1"
            );
            // (this.props.hostSiteUrl || this.props.context.siteUrl) +
            // `/_layouts/15/userphoto.aspx?size=S&accountname=${
            //   persons[index].User.Email ||
            //   persons[index].User.Key.substr(
            //     persons[index].User.Key.lastIndexOf("|") + 1
            //   )
            // }`;
          });
          return persons;
        })
        .then(
          (persons: any) => {
            //const batch = this.props.spHttpClient.beginBatch();
            const ensureUserUrl = `${this.props.context.siteUrl}/_api/web/ensureUser`;
            const batchPromises: Promise<IEnsureUser>[] = persons.map(
              (p: SharePointUserPersona) => {
                p.primaryText = p.User.DisplayText;
                p.secondaryText = p.User.EntityData.Title;
                var userQuery = { logonName: p.User.Key };
                return (
                  this.props.context.client
                    .post(ensureUserUrl, userQuery)
                    //  return this.props.spHttpClient.post(ensureUserUrl,
                    //                                       SPHttpClient.configurations.v1,
                    //                                       {body:JSON.stringify({logonName:  p.User.Key})})
                    .then((response: any) => {
                      return response.data.d;
                    })
                    .then((json: IEnsureUser) => json)
                );
              }
            );

            // var users = this.props.spHttpClient.execute().then(() => );
            var users = Promise.all(batchPromises).then((values: any) => {
              values.forEach((v: any) => {
                let userPersona = lodash.find(
                  persons,
                  (o: any) => o.User.Key == v.LoginName
                );
                if (userPersona && userPersona.User) {
                  let user = userPersona.User;
                  lodash.assign(user, v);
                  userPersona.User = user;
                }
              });

              resolve(persons);
            });
          },
          (error: any): void => {
            reject((this._peopleList = []));
          }
        )
    );
  }

  private _filterPersonasByText(filterText: string): IPersonaProps[] {
    return this._peopleList.filter((item: any) =>
      this._doesTextStartWith(item.primaryText, filterText)
    );
  }

  private _removeDuplicates(
    personas: IPersonaProps[],
    possibleDupes: IPersonaProps[]
  ) {
    return personas.filter(
      (persona) => !this._listContainsPersona(persona, possibleDupes)
    );
  }
  private _listContainsPersona(
    persona: IPersonaProps,
    personas: IPersonaProps[]
  ) {
    if (!personas || !personas.length || personas.length === 0) {
      return false;
    }
    return (
      personas.filter((item) => item.primaryText === persona.primaryText)
        .length > 0
    );
  }
  private _filterPromise(
    personasToReturn: IPersonaProps[]
  ): IPersonaProps[] | Promise<IPersonaProps[]> {
    if (this.state.delayResults) {
      return this._convertResultsToPromise(personasToReturn);
    } else {
      return personasToReturn;
    }
  }
  private _convertResultsToPromise(
    results: IPersonaProps[]
  ): Promise<IPersonaProps[]> {
    return new Promise<IPersonaProps[]>((resolve: any, reject: any) =>
      setTimeout(() => resolve(results), 2000)
    );
  }
  private _doesTextStartWith(text: string, filterText: string): boolean {
    return text.toLowerCase().indexOf(filterText.toLowerCase()) === 0;
  }
}
