import {Component, h, State, Listen, Prop, Event, EventEmitter, Element} from '@stencil/core';
import {IActivityOption, TActivityDateInterval} from '../../types/activity';
import {getActivityParamOptions} from '../../helpers/activity';
import {IArtistFilters} from '../../types/artists';
import {IEventsFilter} from '../../types/events';
import {IPostalCodeFilter, IMarketOption, IPostalCodeOption} from '../../types/locations';
import {safeParseInt} from '../../helpers/common';
import {getValueFromEncodedString, isEmptyArray, isNotEmpty, isNotEmptyString} from "../../helpers/data.helper";
import {FormInput} from "../../objects/form-input";
import {IIdentifiedObject} from '../../types/common';
import {AudienceService} from '../../services/audience';
import {IDmasFilter} from "../../types/dmas";
import _ from 'lodash';
import {
  step1Preset,
  step2Preset,
  step3Preset,
  step4Preset,
  step5Preset,
  step6Preset, step7Preset
} from "../../helpers/audience-size-presets";
import {AJAX_BASE_URL} from "../../config/main";
//import {StoreService} from "../../services/store.service";
//import {VALUE_LOADED} from "../../redux/const";

//todo: add support for other filters
interface IAudienceFilters {
  artists?: IArtistFilters,
  events?: IEventsFilter,
  postalCodes?: IPostalCodeFilter,
  dmas?: IDmasFilter,
  lastPurchased?: TActivityDateInterval,
  lastOpened?: TActivityDateInterval,
  markets?: any[],
  lastWeekSends?: number,
  newsletterId?: number,
}

@Component({
  tag: 'lemi-audience-builder',
  styleUrls: ['./lemi-audience-builder.scss', '../../../node_modules/@bubbleup/ln-webix-skin/assets/webix-livenation.css'],
  assetsDirs: ['./', '../../../node_modules/@bubbleup/ln-webix-skin/assets/'],
  shadow: false,
})
export class LemiAudienceBuilder {

  audienceConfig: IAudienceFilters = {};

  artistsEl!: HTMLLemiArtistsElement;
  eventsEl!: HTMLLemiEventsElement;
  postalCodesEl!: HTMLLemiPostalCodesElement;
  marketsEl!: HTMLLemiMarketsElement;
  audienceSizeSliderEl!: HTMLWebixSliderElement;

  lastOpenEl!: HTMLLemiToggleOptionElement;
  lastPurchasedEl!: HTMLLemiToggleOptionElement;

  artistsCardEl!: HTMLLemiCardElement;
  activityCardEl!: HTMLLemiCardElement;
  locationCardEl!: HTMLLemiCardElement;

  @Prop() name: string;
  @Prop() id: string = '';
  @Prop() value: any;

  @Prop() allowed_markets: string;

  @Prop() selected_artist_ids: any;
  @Prop() selected_event_ids: any;
  @Prop() selected_dma_ids: any;
  @Prop() api_url: any;
  @Prop() enable_slider: string;
  @Prop() cpm: string;
  @Prop() show_include_primary_event_purchasers: string;
  @Prop() show_exclude_primary_event_purchasers: string;
  @Prop() show_include_attracted_to_primary_artist: string;
  @Prop() last_import_date: string;

  protected selectedArtistIds: string[];
  protected selectedEvents: IIdentifiedObject[];
  protected selectedDmas: IIdentifiedObject[];

  protected hiddenInputId: string;

  protected sizeSliderValue = "4";
  @State() sizeSliderVisible = false;
  protected sizeSliderMoved = false;

  @Prop() artists_data: any;
  @Prop() events_data: any;
  @Prop() dmas_data: any;
  @Prop() is_user_admin: any;
  @Prop() display_allowed_markets: any;
  @Prop() show_markets_selector: string;
  @Prop() newsletter_id: any;
  @Prop() show_tick_marks: any;

  protected artistsData: any;
  protected eventsData: any;
  protected dmasData: any;
  protected isUserAdmin: boolean;
  protected allowedMarkets: any;
  protected audienceSizeLoadedTimes = 0;
  protected displayAllowedMarkets: boolean;
  protected showMarketsSelector: boolean;
  protected enableSlider: boolean;
  protected showTickMarks: boolean;
  protected showIncludePrimaryEventPurchasers: boolean;
  protected showExcludePrimaryEventPurchasers: boolean;
  protected showIncludeAttractedToPrimaryArtist: boolean;

  //public storeService: StoreService;

  @State() _fieldValue: any;

  @State() lastOpenOption: IActivityOption = {
    label: "Last Open",
    enabled: true,
    params: {range: '1 year'}
  };

  @State() lastPurchaseOption: IActivityOption = {
    label: "Last Purchase",
    enabled: true,
    params: {range: '1 year'}
  };

  @State() audienceSize: number = 0;

  //Inputs
  @State() artistsCardInput: FormInput;
  @State() activityCardInput: FormInput;
  @State() sizeSliderCardInput: FormInput;
  @State() artistsInput: FormInput;
  @State() activityInput: any;
  @State() locationCardInput: any;
  @State() locationInput: any;
  @State() frequencyCapInput: any;

  @State() audienceFetchInProgress: boolean = false;

  @Element() el!: HTMLLemiAudienceBuilderElement;
  @Event() audienceChanged: EventEmitter;

  constructor() {
    /*   this.storeService = new StoreService();

       var store = this.storeService;
       this.storeService.getStore().subscribe(() => {
         console.log(store);
       });*/
  }

  @Listen('stateChanged')
  async handleStateChange() {

    this.audienceConfig = await this.getAudienceFilters();

    if (Object.entries(this.audienceConfig).length > 0) {

      let queryParams = [];

      if (this.audienceConfig.artists) {
        if (this.audienceConfig.artists.affinity) {
          queryParams = queryParams.concat(this.audienceConfig.artists.affinity.map(attractionId => `attractionIds[]=${attractionId}`));
        }

        if (this.audienceConfig.artists.purchased) {
          queryParams = queryParams.concat(this.audienceConfig.artists.purchased.map(artistId => `artistIds[]=${artistId}`));
        }

        if (this.audienceConfig.artists.excludedArtistIds) {
          queryParams = queryParams.concat(this.audienceConfig.artists.excludedArtistIds.map(artistId => `excludedArtistIds[]=${artistId}`));
        }

        if (this.audienceConfig.artists.excludedAttractionIds) {
          queryParams = queryParams.concat(this.audienceConfig.artists.excludedAttractionIds.map(artistId => `excludedAttractionIds[]=${artistId}`));
        }
      }

      if (this.audienceConfig.events) {
        queryParams = queryParams.concat(
          this.audienceConfig.events.events.filter(event => event.params.filterType === 'include')
            .map(event => `eventIds[]=${event.id}`)
        ).concat(
          this.audienceConfig.events.events.filter(event => event.params.filterType === 'exclude')
            .map(event => `excludedEventIds[]=${event.id}`)
        );

        if (this.frequencyCapInput.value.includeIfAlreadyPurchasedTicketToPrimaryEvent) {
          queryParams = queryParams.concat('primaryEventId=' + this.audienceConfig.events.events[0].id);
          queryParams = queryParams.concat('requirePrimaryEventPurchase=1');
        }
      }

      if (this.audienceConfig.postalCodes && !isEmptyArray(this.audienceConfig.postalCodes.postalCodes)) {
        queryParams = queryParams.concat(
          this.audienceConfig.postalCodes.postalCodes.filter(postalCode => {
            return postalCode.enabled && postalCode.params.radius !== 'exclude'
          })
            .map(postalCode => `zipCodes[]=${postalCode.label}` + (safeParseInt(postalCode.params.radius) > 0 ? `:${postalCode.params.radius}` : ''))
        ).concat(this.audienceConfig.postalCodes.postalCodes.filter(postalCode => {
          return postalCode.enabled && postalCode.params.radius === 'exclude'
        })
          .map(postalCode => `excludedZipCodes[]=${postalCode.label}`));
      }

      if (!isEmptyArray(this.audienceConfig.markets)) {

        let selectedDmaIds = [];

        this.audienceConfig.markets.filter(market => {
          return !isEmptyArray(market.dmas);
        }).forEach(market => {
          market.dmas.filter(dma => dma.enabled).forEach(dma => {
            selectedDmaIds.push(dma.id);
          })
        });

        queryParams = queryParams.concat(
          this.audienceConfig.markets.filter(market => {

            let marketDmasEnabled = [];

            if (!isEmptyArray(market.dmas)) {
              marketDmasEnabled = market.dmas.filter(dma => {
                return dma.enabled;
              });
            }

            return isEmptyArray(marketDmasEnabled);
          }).map(market => `marketIds[]=${market.id}`)
        );

        queryParams = queryParams.concat(selectedDmaIds.map(dmaId => `dmaIds[]=${dmaId}`));
      } else {
        if (!isEmptyArray(this.allowedMarkets)) {
          if (this.allowedMarkets.length === 1) {
            queryParams = queryParams.concat(this.allowedMarkets.map(market => `marketIds[]=${market.id}`));
          }
        }
      }

      if (this.audienceConfig.lastOpened) {
        queryParams = queryParams.concat([`lastOpen=${this.audienceConfig.lastOpened}`]);
      }

      if (this.audienceConfig.lastPurchased) {
        queryParams = queryParams.concat([`lastPurchase=${this.audienceConfig.lastPurchased}`]);
      }

      if (this.audienceConfig.lastWeekSends) {
        queryParams = queryParams.concat([`lastWeekSends=${this.audienceConfig.lastWeekSends}`])
      }

      if (isNotEmptyString(this.newsletter_id)) {
        queryParams = queryParams.concat([`newsletterId=${this.newsletter_id}`])
      }

      if (isNotEmptyString(this.last_import_date)) {
        queryParams = queryParams.concat([`lastImported=${this.last_import_date}`]);
      }

      if (queryParams) {
        // AudienceService.fetchAudienceSize(queryParams);
        this.audienceChanged.emit(queryParams.join('&'));
        this.renderFormData();
      }
    }

  }

  componentWillLoad() {

    this.isUserAdmin = (this.is_user_admin === "1");
    this.enableSlider = (this.enable_slider === "1");
    this.showMarketsSelector = (this.show_markets_selector === "1");
    this.showIncludePrimaryEventPurchasers = (this.show_include_primary_event_purchasers === "1");
    this.showExcludePrimaryEventPurchasers = (this.show_exclude_primary_event_purchasers === "1");
    this.showIncludeAttractedToPrimaryArtist = (this.show_include_attracted_to_primary_artist === "1");
    this.showTickMarks = (this.show_tick_marks === "1");

    if (isNotEmptyString(this.value)) {
      this._fieldValue = JSON.parse(this.value);
      this.value = this._fieldValue;
    } else {
      this.value = null;
    }

    (window as any).lemi_connect_url = this.api_url;

    if (this.display_allowed_markets === "1") {
      if (isNotEmpty(this.value)) {
        this.displayAllowedMarkets = false;
      } else {
        this.displayAllowedMarkets = true;
      }
    }

    if (!isNotEmpty(this.value)) {
      this.sizeSliderVisible = true;
      this.sizeSliderMoved = true;
    }

    if (this.id) {
      this.hiddenInputId = this.id.replace(/\W/g, '_').toLowerCase() + '_hiddenInput';
    }

    if (isNotEmptyString(this.selected_artist_ids)) {
      this.selectedArtistIds = getValueFromEncodedString(this.selected_artist_ids);
    }

    if (isNotEmptyString(this.artists_data)) {
      this.artistsData = getValueFromEncodedString(this.artists_data);
    }

    if (isNotEmptyString(this.selected_event_ids)) {
      this.selectedEvents = getValueFromEncodedString(this.selected_event_ids).map(eventId => {
        return {
          id: eventId
        }
      });
    }

    if (isNotEmpty(this.events_data)) {
      this.eventsData = getValueFromEncodedString(this.events_data);
    }

    if (isNotEmpty(this.dmas_data)) {
      this.dmasData = getValueFromEncodedString(this.dmas_data);
    }

    if (isNotEmpty(this.allowed_markets)) {
      this.allowedMarkets = getValueFromEncodedString(this.allowed_markets);
    }

    /*
    if (isNotEmpty(this.value)) {
      this.storeService.getStore().dispatch({
        type: VALUE_LOADED,
        value: this.value
      });
    }*/

    this.sizeSliderCardInput = new FormInput({
      label: "Audience Size",
      name: "audienceSize",
      id: "audienceSize",
      value: (isNotEmpty(this.value) ? false : true),
    });

    if (!this.enableSlider) {
      this.sizeSliderCardInput.value = false;
    }

    this.artistsCardInput = new FormInput({
      label: "Artists",
      name: "artists",
      id: "artists",
      value: (isNotEmpty(this.value) ? this.value.artistsChecked : true),
    });

    this.activityCardInput = new FormInput({
      label: "Activity",
      name: "activity",
      id: "activity",
      value: (isNotEmpty(this.value) ? this.value.activityChecked : true),
    });

    this.artistsInput = new FormInput({
      label: "Artists",
      name: "artists",
      id: "artists",
      value: (isNotEmpty(this.value) && isNotEmpty(this.value.artists) ? this.value.artists : []),
    });

    this.activityInput = new FormInput({
      label: "Activity",
      name: "activity",
      id: "activity",
      value: _.get(this.value, 'activity', {
        lastOpenChecked: true,
        lastOpen: '1 year',
        lastPurchasedChecked: true,
        lastPurchased: '1 year',
        events: []
      }),
    });

    if (isNotEmpty(this.value) && isNotEmpty(this.value.activity)) {
      this.lastOpenOption = {
        label: "Last Open",
        enabled: true,
        params: {range: isNotEmpty(this.value.activity.lastOpen) ? this.value.activity.lastOpen : '1 year'}
      };

      this.lastPurchaseOption = {
        label: "Last Purchase",
        enabled: true,
        params: {range: isNotEmpty(this.value.activity.lastPurchased) ? this.value.activity.lastPurchased : '1 year'}
      };
    }

    this.locationCardInput = new FormInput({
      label: "Location",
      name: "location",
      id: "location",
      value: (isNotEmpty(this.value) ? (this.value.locationChecked ? true : false) : true),
    });

    this.locationInput = new FormInput({
      label: "Location",
      name: "location",
      id: "location",
      value: (isNotEmpty(this.value) && isNotEmpty(this.value.location) ? this.value.location : {
        markets: [],
        postalCodes: []
      }),
    });

    if (!isEmptyArray(this.locationInput.value.markets) && this.locationInput.value.markets.length === 1) {
      this.locationInput.value.markets[0].enabled = true;
    }

    this.frequencyCapInput = new FormInput({
      label: "Frequency Cap",
      name: "frequencyCap",
      id: "frequencyCap",
      value: (isNotEmpty(this.value) && isNotEmpty(this.value.frequencyCap) ? this.value.frequencyCap : {
        excludeIf5EmailsReceivedInLastWeek: true,
        includeIfAttractedToPrimaryArtist: this.showIncludeAttractedToPrimaryArtist,
        excludeIfAlreadyPurchasedTicketToPrimaryEvent: this.showExcludePrimaryEventPurchasers,
        includeIfAlreadyPurchasedTicketToPrimaryEvent: this.showIncludePrimaryEventPurchasers,
      }),
    });

    if (isNotEmpty(this.selectedEvents)) {
      this.selectedEvents.forEach(event => {
        let eventData = null;

        if (isNotEmpty(this.eventsData)) {
          eventData = this.eventsData.filter(evt => safeParseInt(evt.id) === safeParseInt(event.id));
        }

        if (!isNotEmpty(this.value)) {
          if (isNotEmpty(eventData) && isNotEmpty(eventData[0]) && isNotEmpty(eventData[0].venue_zip)) {
            this.addPostalCodesByEvents([eventData[0].venue_zip]);
          }
        }
      });
    }

    if (!isNotEmpty(this.value)) {
      this.sizeSliderCardInput.value = true;
      this.sizeSliderValue = '4';
      this.applyPreset(step4Preset());
    } else {
      this.sizeSliderCardInput.value = false;
      this.sizeSliderValue = isNotEmpty(this.value.sizeSliderValue) ? this.value.sizeSliderValue : '4';
    }

    this.renderFormData();

    AudienceService.listen(this.el, 'audienceChanged');

    AudienceService.size.subscribe(data => {
      this.audienceSize = data;
    });

    AudienceService.inProgress.subscribe(data => {
      this.audienceFetchInProgress = data
    });
  }

  componentDidLoad() {
    this.handleStateChange();
  }

  renderFormData() {
    this._fieldValue = {
      artistsChecked: this.artistsCardInput.value,
      activityChecked: this.activityCardInput.value,
      artists: this.artistsInput.value,
      activity: this.activityInput.value,
      locationChecked: this.locationCardInput.value,
      location: this.locationInput.value,
      frequencyCap: this.frequencyCapInput.value,
      audienceSize: this.audienceSize,
      campaignCost: this.campaignCost.toLocaleString('en-US', {style: 'currency', currency: 'USD'}),
      sizeSliderValue: this.sizeSliderValue
    };
  }

  @Listen('disableSlider')
  handleDisableSliderEvent() {
    this.disableSlider();
  }

  protected disableSlider() {
    if (this.sizeSliderVisible) {
      this.sizeSliderVisible = false;
      this.sizeSliderCardInput = {
        ...this.sizeSliderCardInput,
        value: false,
      };
    }
  }

  protected processArtistSelectChange(event) {
    this.artistsInput.value = event.detail.value;
    this.renderFormData();
  }

  protected processArtistCheckChange(event) {
    if (event.target.tagName === 'LEMI-CARD') {
      this.artistsCardInput.value = event.detail.value;
      this.renderFormData();
    }
  }

  protected processActivityCheckChange(event) {
    if (event.target.tagName === 'LEMI-CARD') {
      this.activityCardInput.value = event.detail.value;
      this.renderFormData();
    }
  }

  protected processLocationCheckChange(event) {
    if (event.target.tagName === 'LEMI-CARD') {
      this.locationCardInput.value = event.detail.value;
      this.renderFormData();
    }
  }

  protected processLastOpenCheckChange(event) {
    if (event.target.tagName === 'LEMI-TOGGLE-OPTION') {
      this.activityInput.value.lastOpenChecked = event.detail.value;
      this.renderFormData();
    }
  }

  protected processLastOpenSelectChange(event) {
    this.activityInput.value.lastOpen = event.detail;
    this.renderFormData();
  }

  protected processLastPurchaseCheckChange(event) {
    if (event.target.tagName === 'LEMI-TOGGLE-OPTION') {
      this.activityInput.value.lastPurchasedChecked = event.detail.value;
      this.renderFormData();
    }
  }

  protected processLastPurchaseSelectChange(event) {
    this.activityInput.value.lastPurchased = event.detail;
    this.renderFormData();
  }

  protected processEventFiltersChanged(event) {
    this.activityInput.value.events = event.detail.value;
    this.renderFormData();
  }

  protected processMarketsFiltersChanged(event) {
    if (event.target.tagName === 'LEMI-MARKETS') {
      this.locationInput.value.markets = event.detail.value;
      this.sizeSliderMoved = true;
      this.renderFormData();
    }
  }

  protected processDmaFiltersChanged(event) {
    this.locationInput.value.dmas = event.detail.value;
    this.renderFormData();
  }

  //todo: this process shouldn't run if loading a previously saved set of filters - only on init of a new Audience
  protected addPostalCodesByEvents(postalCodes) {

    let currentPostalCodes = this.locationInput.value.postalCodes ? this.locationInput.value.postalCodes.map(postalCodeEntry => {
      return postalCodeEntry.postalCode;
    }) : [];

    postalCodes.forEach(newPostalCode => {

      if (newPostalCode && !currentPostalCodes.includes(newPostalCode)) {
        if (this.locationInput.value.postalCodes) {

          this.locationInput.value.postalCodes.push({
            label: newPostalCode,
            params: {
              radius: 0,
            }
          } as IPostalCodeOption);

        } else {

          this.locationInput.value.postalCodes = [{
            label: newPostalCode,
            params: {
              radius: 0,
            }
          } as IPostalCodeOption];

        }
      }
    });

    this.locationInput = new FormInput({
      label: this.locationInput.label,
      name: this.locationInput.name,
      id: this.locationInput.id,
      value: this.locationInput.value,
    });
  }

  protected processLocationMarketCheckChanged(event) {
    if (event.target.tagName === 'LEMI-CARD') {
      this.locationInput.value.marketChecked = event.detail.value;
      this.renderFormData();
    }
  }

  protected processPostalCodesSelectChanged(event) {
    this.locationInput.value.postalCodes = event.detail.value;
    this.renderFormData();
  }


  protected processSizeSliderCheckChange(event) {
    this.sizeSliderCardInput.value = event.detail.value;

    if (this.sizeSliderCardInput.value) {
      this.audienceSizeSliderEl.enableSlider();
    } else {
      this.audienceSizeSliderEl.disableSlider();
    }

    this.renderFormData();
  }

  async getAudienceFilters(): Promise<IAudienceFilters> {
    const [
      artistFilters,
      eventFilters,
      marketFilters,
      postalCodeFilters,
      artistsEnabled,
      activityEnabled,
      locationsEnabled,
      frequencyCapEnabled
    ] = await Promise.all([
      this.artistsEl.getFilters(),
      this.eventsEl.getFilters(),
      this.marketsEl.getFilters(),
      this.postalCodesEl.getFilters(),
      this.artistsCardEl.getEnabled(),
      this.activityCardEl.getEnabled(),
      this.locationCardEl.getEnabled(),
      this.getFrequencyCapEnabled()
    ]);

    const filters: IAudienceFilters = {};

    if (artistsEnabled) {

      filters.artists = artistFilters;

    } else if (frequencyCapEnabled && this.selectedArtistIds) {

      let selectedArtistAffinities = this.artistsData.filter(artistData => {
        return this.selectedArtistIds.includes(artistData.id);
      }).map(artistData => {
        return artistData.attraction_id;
      });

      filters.artists = {
        affinity: artistFilters.affinity.filter(artistId => {
          return selectedArtistAffinities.includes(artistId + '');
        }),
        purchased: artistFilters.purchased.filter(artistId => {
          return this.selectedArtistIds.includes(artistId + '');
        }),
        excludedArtistIds: artistFilters.excludedArtistIds.filter(artistId => {
          return this.selectedArtistIds.includes(artistId + '');
        }),
        excludedAttractionIds: []
      };
    }

    if (activityEnabled) {
      filters.events = eventFilters;
      if (this.activityInput.value.lastOpenChecked) {
        filters.lastOpened = this.activityInput.value.lastOpen;
      }
      if (this.activityInput.value.lastPurchasedChecked) {
        filters.lastPurchased = this.activityInput.value.lastPurchased;
      }

    } else if (frequencyCapEnabled && this.selectedEvents) {
      filters.events = {
        events: eventFilters.events.filter(event => {
          return this.selectedEvents.find(selectedEvent => {
            return selectedEvent.id === event.id;
          });
        })
      }
    }


    if (locationsEnabled) {
      filters.markets = marketFilters;
      filters.postalCodes = postalCodeFilters;
    }

    if (this.frequencyCapInput.value.excludeIf5EmailsReceivedInLastWeek) {
      filters.lastWeekSends = 3;
    }

    return filters;
  }

  get campaignCost() {
    return Math.ceil(this.audienceSize * parseFloat(this.cpm) * 100) / 100;
  }

  protected processExcludeIf5EmailsReceivedInLastWeekToggle(e) {
    this.frequencyCapInput.value.excludeIf5EmailsReceivedInLastWeek = e.target.querySelector('input[type="checkbox"]').checked;
    this.renderFormData();
  }

  protected processIncludeIfAttractedToPrimaryArtistToggle(e) {
    this.frequencyCapInput.value.includeIfAttractedToPrimaryArtist = e.target.querySelector('input[type="checkbox"]').checked;
    this.renderFormData();
  }

  protected processExcludeIfAlreadyPurchasedTicketToPrimaryEventToggle(e) {
    this.frequencyCapInput.value.excludeIfAlreadyPurchasedTicketToPrimaryEvent = e.target.querySelector('input[type="checkbox"]').checked;

    if (this.frequencyCapInput.value.excludeIfAlreadyPurchasedTicketToPrimaryEvent) {
      this.frequencyCapInput.value.includeIfAlreadyPurchasedTicketToPrimaryEvent = !this.frequencyCapInput.value.excludeIfAlreadyPurchasedTicketToPrimaryEvent;
    }

    this.renderFormData();
  }

  protected processIncludeIfAlreadyPurchasedTicketToPrimaryEventToggle(e) {
    this.frequencyCapInput.value.includeIfAlreadyPurchasedTicketToPrimaryEvent = e.target.querySelector('input[type="checkbox"]').checked;

    if (this.frequencyCapInput.value.includeIfAlreadyPurchasedTicketToPrimaryEvent) {
      this.frequencyCapInput.value.excludeIfAlreadyPurchasedTicketToPrimaryEvent = !this.frequencyCapInput.value.includeIfAlreadyPurchasedTicketToPrimaryEvent;
    }

    this.renderFormData();
  }

  protected getFrequencyCapEnabled() {
    return (this.frequencyCapInput.value.excludeIf5EmailsReceivedInLastWeek ||
      this.frequencyCapInput.value.excludeIfAlreadyPurchasedTicketToPrimaryEvent ||
      this.frequencyCapInput.value.includeIfAlreadyPurchasedTicketToPrimaryEvent ||
      this.frequencyCapInput.value.includeIfAttractedToPrimaryArtist);
  }

  protected processAudienceSliderStateChange(event) {
    this.sizeSliderValue = event.detail.value;
    this.processSizeSliderPresetSelected();
  }

  protected applyPreset(preset) {

    if (preset.artists &&
      !isEmptyArray(this.artistsInput.value)) {

      if (preset.artists.primaryArtist) {

        if (this.artistsInput.value[0].attraction_id) {
          this.artistsInput.value[0].affinity = preset.artists.primaryArtist.affinity;
          this.artistsInput.value[0].purchase = preset.artists.primaryArtist.purchase;
        }

      }

      if (isNotEmpty(this.selectedArtistIds)) {

        this.artistsInput.value = this.artistsInput.value.filter((artist) => {
          return this.selectedArtistIds.includes(artist.id + '');
        });

      } else {
        this.artistsInput.value = [this.artistsInput.value[0]];
      }
    }

    if (preset.activity) {
      this.activityInput.value.lastOpenChecked = preset.activity.lastOpenChecked;
      this.activityInput.value.lastOpen = preset.activity.lastOpen;
      this.activityInput.value.lastPurchasedChecked = preset.activity.lastPurchasedChecked;
      this.activityInput.value.lastPurchased = preset.activity.lastPurchased;

      if (!isEmptyArray(this.activityInput.value.events)) {

        if (preset.activity.primaryEvent) {
          if (this.showIncludePrimaryEventPurchasers &&
            preset.activity.primaryEvent.filterType === 'exclude') {
            this.frequencyCapInput.value.includeIfAlreadyPurchasedTicketToPrimaryEvent = false;
          }

          this.activityInput.value.events[0].filterType = preset.activity.primaryEvent.filterType;
        }

        this.activityInput.value.events = [this.activityInput.value.events[0]];
      }
    }

    if (preset.artists.addAllEventArtists) {
      this.addEventArtists();
    }

    if (preset.artists.addArtistsRelatedToPrimaryArtist > 0) {
      this.addRelatedArtists(preset.artists.addArtistsRelatedToPrimaryArtist);
    }

    if (preset.location.primaryPostalCode &&
      !isEmptyArray(this.locationInput.value.postalCodes)) {
      this.locationInput.value.postalCodes[0].params.radius = preset.location.primaryPostalCode.radius;
      this.locationInput.value.postalCodes[0].enabled = preset.location.primaryPostalCode.enabled;
    }

    this.disableExtraPostalCodes();

  }

  protected processSizeSliderPresetSelected() {
    this.sizeSliderMoved = true;

    switch (this.sizeSliderValue) {
      case '1':
        this.applyPreset(step1Preset());
        break;

      case '2':
        this.applyPreset(step2Preset());
        break;

      case '3':
        this.applyPreset(step3Preset());
        break;

      case '4':
        this.applyPreset(step4Preset());
        break;

      case '5':
        this.applyPreset(step5Preset());
        break;

      case '6':
        this.applyPreset(step6Preset());
        break;

      case '7':
        this.applyPreset(step7Preset());
        break;
    }

    this.artistsEl.setSelectionByValue(this.artistsInput.value);
    this.eventsEl.setSelectionByValue(this.activityInput.value.events);
    this.postalCodesEl.reloadPostalCodes(this.locationInput.value.postalCodes);

    this.renderFormData();
  }

  protected disableExtraPostalCodes() {

    if (!isEmptyArray(this.locationInput.value.postalCodes) &&
      this.locationInput.value.postalCodes.length > 1) {

      this.locationInput.value.postalCodes.forEach((code, index) => {
        console.debug(code);
        if (index > 0) {
          this.locationInput.value.postalCodes[index].enabled = false;
        }
      });
    }
  }

  protected addEventArtists() {
    let eventIds = this.activityInput.value.events.map(event => {
      return event.id
    });

    if (!isEmptyArray(eventIds)) {
      this.fetchArtistsForEvents(eventIds).then(artistsData => {

        if (!isEmptyArray(artistsData)) {
          artistsData.forEach(artistData => {

            //todo: make sure this works w/ records that have null artist_id
            if (!this.artistsInput.value.map(artist => {
              return safeParseInt(artist.id);
            }).includes(safeParseInt(artistData.id))) {

              this.artistsInput.value.push({
                id: safeParseInt(artistData.id),
                label: artistData.text,
                attraction_id: artistData.attraction_id ? safeParseInt(artistData.attraction_id) : null,
                affinity: artistData.attraction_id ? true : false,
                // purchase: true,
                purchase: artistData.id ? true : false,
              })
            }
          });

          this.artistsEl.setSelectionByValue(this.artistsInput.value);
        }
      })
    }
  }

  protected addRelatedArtists(limit) {
    if (!isEmptyArray(this.artistsInput.value)) {

      const artistIds = [];

      this.artistsInput.value.forEach(artist => {
        artistIds.push(artist.id);
      });

      this.fetchRelatedArtists(artistIds).then(relatedArtists => {
        if (!isEmptyArray(relatedArtists)) {

          relatedArtists.slice(0, limit).forEach(relatedArtist => {

            //todo: make sure this works w/ records that have null artist_id
            let artistIndex = this.artistsInput.value.map(artist => {
              return safeParseInt(artist.id);
            }).indexOf(safeParseInt(relatedArtist.id));

            if (artistIndex === -1) {

              this.artistsInput.value.push({
                id: safeParseInt(relatedArtist.id),
                label: relatedArtist.text,
                attraction_id: relatedArtist.attraction_id ? safeParseInt(relatedArtist.attraction_id) : null,
                affinity: relatedArtist.attraction_id ? true : false,
                // purchase: true,
                purchase: relatedArtist.id ? true : false,
              })
            } else {
              this.artistsInput.value[artistIndex].enabled = true;
            }
          });
        }

        this.artistsEl.setSelectionByValue(this.artistsInput.value);
      });
    }
  }

  protected async fetchRelatedArtists(artistId) {
    let requestUrl = this.api_url + AJAX_BASE_URL + '/find-related-artists?term=' + artistId;
    let response = await fetch(requestUrl);
    return await response.json();
  }

  protected async fetchArtistsForEvents(eventIds) {

    let requestUrl = this.api_url + AJAX_BASE_URL + '/get-events-artists?';

    eventIds.forEach(eventId => {
      requestUrl += 'eventIds[]=' + eventId + '&'
    });

    let response = await fetch(requestUrl);
    return await response.json();
  }

  protected processAudienceSliderTouch(event) {
    if (!this.sizeSliderVisible) {
      let sliderRect = this.audienceSizeSliderEl.getBoundingClientRect();
      let clickPos = event.clientX - sliderRect.left;
      let stepSize = sliderRect.width / (this.audienceSizeSliderEl.max - this.audienceSizeSliderEl.min);
      this.sizeSliderValue = Math.round(clickPos / stepSize) + 1 + '';
      this.sizeSliderVisible = true;
      this.processSizeSliderPresetSelected();
    }
  }

  getMarketParamOptions(marketId: number | string): IMarketOption[] {
    if (this.allowedMarkets) {
      return this.allowedMarkets.map(allowedMarket => {
        return {
          ...allowedMarket,
          selected: (safeParseInt(allowedMarket.value) === safeParseInt(marketId)),
        };
      });
    }
  }

  render() {
    return (

      <div class="lemi-audience-builder">
        <input type="hidden"
               id={this.hiddenInputId}
               name={this.name}
               value={JSON.stringify(this._fieldValue)}/>

        <div class="mt-1 mb-1 row">
          <div class="col-sm-8 audience-size">

            <lemi-card col-size="12"
                       allowToggle={this.enableSlider}
                       inputData={this.sizeSliderCardInput}
                       card-title={this.sizeSliderCardInput.label}
                       onStateChanged={e => {
                         this.processSizeSliderCheckChange(e);
                       }}>
              <div class="">
                <webix-slider
                  ref={el => {
                    this.audienceSizeSliderEl = el as HTMLWebixSliderElement;
                  }}
                  min={1}
                  max={7}
                  step={1}
                  visible={this.sizeSliderVisible}
                  showTickMarks={this.showTickMarks}
                  disabled={!this.enableSlider}
                  value={this.sizeSliderValue}
                  onSliderChange={(e) => {
                    if (this.enableSlider) {
                      this.processAudienceSliderStateChange(e);
                    }
                  }}
                  onSliderMouseDown={(e) => {
                    if (this.enableSlider) {
                      this.processAudienceSliderTouch(e);
                    }
                  }}
                  cssClass={'audience-size--range ' + (this.sizeSliderVisible && this.enableSlider ? '' : 'inactive')}
                ></webix-slider>
                <datalist id={`${this.hiddenInputId}-range-values`}>
                  {[1, 2, 3, 4, 5, 6, 7].map(val => <option value={val}></option>)}
                </datalist>
              </div>

              <div class="col-sm-12">
                <strong class={this.sizeSliderCardInput.value === true ? '' : 'hide'}>
                  Warning: adjusting this slider will overwrite any changes you have made to the filters below.
                </strong>
              </div>

            </lemi-card>

          </div>
          <lemi-card col-size="4" card-title="Audience Estimates" card-id="audience-estimates">
            <div class="row h5">
              <div class="col-xs-7 text-right">
                <label>Estimated Audience Size:</label>
              </div>
              <div class="col-xs-5 text-left">
                <span style={{position: 'relative'}}>
                  {safeParseInt(this.audienceSize).toLocaleString('en-us', {useGrouping: true})}
                  <lemi-preloader loading={this.audienceFetchInProgress}
                                  width={15} containerClass="bg-white align-left">
                  </lemi-preloader>
                </span>
              </div>
            </div>
            <div class="row h5">
              <div class="col-xs-7 text-right">
                <label>Estimated Campaign Cost:</label>
              </div>
              <div class="col-xs-5 text-left">
                <span style={{position: 'relative'}}>
                  {this.campaignCost.toLocaleString('en-US', {style: 'currency', currency: 'USD'})}
                  <lemi-preloader loading={this.audienceFetchInProgress}
                                  width={15} containerClass="bg-white align-left">
                  </lemi-preloader>
                </span>
              </div>
            </div>
            <div class="clearfix"></div>
          </lemi-card>
        </div>

        <div class="row">

          <lemi-card card-title={this.artistsInput.label}
                     inputData={this.artistsCardInput}
                     allowToggle={true}
                     onStateChanged={e => {
                       this.processArtistCheckChange(e);
                     }}
                     ref={el => {
                       this.artistsCardEl = el as HTMLLemiCardElement
                     }}>
            <lemi-artists
              inputValue={this.artistsInput.value}
              frequencyCapIncludeIfAttractedToPrimaryArtist={this.frequencyCapInput.value.includeIfAttractedToPrimaryArtist}
              onArtistFiltersChanged={e => {
                this.processArtistSelectChange(e);
              }}
              ref={el => {
                this.artistsEl = el as HTMLLemiArtistsElement
              }}
              selectedArtists={this.selectedArtistIds}
              artistsData={this.artistsData}
            ></lemi-artists>
          </lemi-card>

          <lemi-card card-title="Activity"
                     allowToggle={true}
                     inputData={this.activityCardInput}
                     ref={el => {
                       this.activityCardEl = el as HTMLLemiCardElement
                     }}
                     onStateChanged={e => {
                       this.processActivityCheckChange(e);
                     }}>

            <div class="lemi-activity-filter no-bottom-border">
              <lemi-toggle-option option={this.lastOpenOption}
                                  ref={el => {
                                    this.lastOpenEl = el as HTMLLemiToggleOptionElement
                                  }}
                                  onStateChanged={(e) => {
                                    this.processLastOpenCheckChange(e)
                                  }}
                                  isChecked={this.activityInput.value.lastOpenChecked}
              >
                <lemi-select options={getActivityParamOptions(this.lastOpenOption)}
                             enabled={this.activityInput.value.lastOpenChecked}
                             optionSelected={this.activityInput.value.lastOpen}
                             onSelectChanged={(e) => {
                               this.processLastOpenSelectChange(e)
                             }}
                ></lemi-select>
              </lemi-toggle-option>
            </div>

            <div class="lemi-activity-filter no-bottom-border">
              <lemi-toggle-option option={this.lastPurchaseOption}
                                  ref={el => {
                                    this.lastPurchasedEl = el as HTMLLemiToggleOptionElement
                                  }}
                                  isChecked={this.activityInput.value.lastPurchasedChecked}
                                  onStateChanged={(e) => {
                                    this.processLastPurchaseCheckChange(e);
                                  }}>
                <lemi-select options={getActivityParamOptions(this.lastPurchaseOption)}
                             enabled={this.activityInput.value.lastPurchasedChecked}
                             optionSelected={this.activityInput.value.lastPurchased}
                             onSelectChanged={(e) => {
                               this.processLastPurchaseSelectChange(e);
                             }}
                ></lemi-select>
              </lemi-toggle-option>
            </div>

            <div class="text-left mt-1">
              <h5>Event Purchases</h5>
            </div>

            <lemi-events ref={el => {
              this.eventsEl = el as HTMLLemiEventsElement
            }}
                         frequencyCapExcludeIfAlreadyPurchasedTicketToPrimaryEvent={this.frequencyCapInput.value.excludeIfAlreadyPurchasedTicketToPrimaryEvent}
                         frequencyCapIncludeIfAlreadyPurchasedTicketToPrimaryEvent={this.frequencyCapInput.value.includeIfAlreadyPurchasedTicketToPrimaryEvent}
                         inputData={this.activityInput}
                         selectedEvents={this.selectedEvents}
                         eventsData={this.eventsData}
                         onEventFiltersChanged={(e) => {
                           this.processEventFiltersChanged(e);
                         }}
            ></lemi-events>

          </lemi-card>

          <lemi-card
            card-title={this.locationCardInput.label}
            inputData={this.locationCardInput}
            ref={el => {
              this.locationCardEl = el as HTMLLemiCardElement
            }}
            allowToggle={true}
            onStateChanged={e => {
              this.processLocationCheckChange(e);
            }}>

            <div class="lemi-market-filter">

              <div class="text-left mt-1">
                <h5>Markets/DMA's</h5>
              </div>

              <lemi-markets ref={el => {
                this.marketsEl = el as HTMLLemiMarketsElement
              }}
                            allowedMarkets={this.allowedMarkets}
                            onStateChanged={(e) => {
                              this.processMarketsFiltersChanged(e);
                            }}
                            showMarketsSelector={this.showMarketsSelector}
                            displayAllowedMarkets={this.displayAllowedMarkets}
                            inputData={this.locationInput.value.markets}>
              </lemi-markets>

            </div>

            <div class="text-left mt-1">
              <h5>Postal Codes</h5>
            </div>

            <lemi-postal-codes ref={el => {
              this.postalCodesEl = el as HTMLLemiPostalCodesElement
            }}
                               postalCodesValue={this.locationInput.value.postalCodes}
                               onPostalCodesSelectChanged={e => this.processPostalCodesSelectChanged(e)}
            ></lemi-postal-codes>

          </lemi-card>

        </div>

        <div class="row">
          <lemi-card col-size="12" card-title="Frequency Cap">
            <div class="lemi-freq-cap-filters">
              <lemi-toggle-option allowToggle={this.isUserAdmin}
                                  option={{
                                    "label": "Exclude if received >= 3 emails in the last week",
                                    "enabled": this.frequencyCapInput.value.excludeIf5EmailsReceivedInLastWeek
                                  }}
                                  onStateChanged={(e) => {
                                    this.processExcludeIf5EmailsReceivedInLastWeekToggle(e)
                                  }}>
              </lemi-toggle-option>
              <lemi-toggle-option allowToggle={this.isUserAdmin}
                                  class={this.showIncludeAttractedToPrimaryArtist ? "" : "hide"}
                                  option={{
                                    "label": "Include if attracted to primary artist",
                                    "enabled": this.frequencyCapInput.value.includeIfAttractedToPrimaryArtist
                                  }}
                                  onStateChanged={(e) => {
                                    this.processIncludeIfAttractedToPrimaryArtistToggle(e)
                                  }}>
              </lemi-toggle-option>
              <lemi-toggle-option
                class={this.showExcludePrimaryEventPurchasers ? "" : "hide"}
                allowToggle={this.isUserAdmin}
                option={{
                  "label": "Exclude if already purchased ticket to primary event",
                  "enabled": this.frequencyCapInput.value.excludeIfAlreadyPurchasedTicketToPrimaryEvent
                }}
                onStateChanged={(e) => {
                  this.processExcludeIfAlreadyPurchasedTicketToPrimaryEventToggle(e)
                }}>
              </lemi-toggle-option>
              <lemi-toggle-option
                class={this.showIncludePrimaryEventPurchasers ? "" : "hide"}
                allowToggle={this.isUserAdmin}
                option={{
                  "label": "Include primary event purchasers",
                  "enabled": this.frequencyCapInput.value.includeIfAlreadyPurchasedTicketToPrimaryEvent
                }}
                onStateChanged={(e) => {
                  this.processIncludeIfAlreadyPurchasedTicketToPrimaryEventToggle(e)
                }}>
              </lemi-toggle-option>
            </div>
          </lemi-card>
        </div>

      </div>

    );
  }

}
