import { CommonModule } from '@angular/common';
import { ChangeDetectorRef, Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
import { NgSelectModule } from '@ng-select/ng-select';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { KeycloakService } from 'keycloak-angular';
import onChange from 'on-change';
import { catchError, concat, debounceTime, distinctUntilChanged, Observable, of, Subject, Subscription, switchMap, tap } from 'rxjs';
import { BusinessListingCriteria, CityAndStateResult, CommercialPropertyListingCriteria, GeoResult, KeycloakUser, UserListingCriteria } from '../../../../../bizmatch-server/src/models/main.model';
import { ModalService } from '../../components/search-modal/modal.service';
import { CriteriaChangeService } from '../../services/criteria-change.service';
import { GeoService } from '../../services/geo.service';
import { ListingsService } from '../../services/listings.service';
import { SearchService } from '../../services/search.service';
import { SelectOptionsService } from '../../services/select-options.service';
import { UserService } from '../../services/user.service';
import { compareObjects, createEmptyBusinessListingCriteria, createEmptyCommercialPropertyListingCriteria, createEmptyUserListingCriteria, getCriteriaStateObject, map2User } from '../../utils/utils';
@UntilDestroy()
@Component({
  selector: 'app-home',
  standalone: true,
  imports: [CommonModule, FormsModule, RouterModule, NgSelectModule],
  templateUrl: './home.component.html',
  styleUrl: './home.component.scss',
})
export class HomeComponent {
  activeTabAction: 'business' | 'commercialProperty' | 'broker' = 'business';
  type: string;
  maxPrice: string;
  minPrice: string;
  criteria: BusinessListingCriteria | CommercialPropertyListingCriteria | UserListingCriteria;
  states = [];
  isMenuOpen = false;
  user: KeycloakUser;
  prompt: string;
  cities$: Observable<CityAndStateResult[]>;
  cityLoading = false;
  cityInput$ = new Subject<string>();
  cityOrState = undefined;
  private criteriaChangeSubscription: Subscription;
  numberOfResults$: Observable<number>;
  public constructor(
    private router: Router,
    private modalService: ModalService,
    private searchService: SearchService,
    private activatedRoute: ActivatedRoute,
    public selectOptions: SelectOptionsService,
    public keycloakService: KeycloakService,
    private criteriaChangeService: CriteriaChangeService,
    private geoService: GeoService,
    public cdRef: ChangeDetectorRef,
    private listingService: ListingsService,
    private userService: UserService,
  ) {}
  async ngOnInit() {
    const token = await this.keycloakService.getToken();
    sessionStorage.removeItem('business_criteria');
    sessionStorage.removeItem('commercialProperty_criteria');
    sessionStorage.removeItem('broker_criteria');
    this.criteria = this.createEnhancedProxy(getCriteriaStateObject('business'));
    this.user = map2User(token);
    this.loadCities();
    this.setupCriteriaChangeListener();
  }
  async changeTab(tabname: 'business' | 'commercialProperty' | 'broker') {
    this.activeTabAction = tabname;
    if ('business' === tabname) {
      this.criteria = this.createEnhancedProxy(getCriteriaStateObject('business'));
    } else if ('commercialProperty' === tabname) {
      this.criteria = this.createEnhancedProxy(getCriteriaStateObject('commercialProperty'));
    } else if ('broker' === tabname) {
      this.criteria = this.createEnhancedProxy(getCriteriaStateObject('broker'));
    } else {
      this.criteria = undefined;
    }
  }
  private createEnhancedProxy(obj: any) {
    const component = this;

    const sessionStorageHandler = function (path, value, previous, applyData) {
      let criteriaType = this.criteriaType;
      sessionStorage.setItem(`${criteriaType}_criteria`, JSON.stringify(this));
    };

    return onChange(obj, function (path, value, previous, applyData) {
      // Call the original sessionStorageHandler
      sessionStorageHandler.call(this, path, value, previous, applyData);

      // Notify about the criteria change using the component's context
      component.criteriaChangeService.notifyCriteriaChange();
    });
  }
  search() {
    this.router.navigate([`${this.activeTabAction}Listings`]);
  }
  private setupCriteriaChangeListener() {
    this.criteriaChangeSubscription = this.criteriaChangeService.criteriaChange$.pipe(untilDestroyed(this), debounceTime(400)).subscribe(() => this.setTotalNumberOfResults());
  }
  login() {
    this.keycloakService.login({
      redirectUri: window.location.href,
    });
  }
  register() {
    this.keycloakService.register({ redirectUri: `${window.location.origin}/account` });
  }
  toggleMenu() {
    this.isMenuOpen = !this.isMenuOpen;
  }
  onTypesChange(value) {
    if (value === '') {
      // Wenn keine Option ausgewählt ist, setzen Sie types zurück auf ein leeres Array
      this.criteria.types = [];
    } else {
      this.criteria.types = [value];
    }
  }
  onRadiusChange(value) {
    if (value === 'null') {
      // Wenn keine Option ausgewählt ist, setzen Sie types zurück auf ein leeres Array
      this.criteria.radius = null;
    } else {
      this.criteria.radius = parseInt(value);
    }
  }
  async openModal() {
    const accepted = await this.modalService.showModal(this.criteria);
    if (accepted) {
      //this.searchService.search(this.criteria);
      this.router.navigate([`${this.activeTabAction}Listings`]);
    }
  }
  private loadCities() {
    this.cities$ = concat(
      of([]), // default items
      this.cityInput$.pipe(
        distinctUntilChanged(),
        tap(() => (this.cityLoading = true)),
        switchMap(term =>
          //this.geoService.findCitiesStartingWith(term).pipe(
          this.geoService.findCitiesAndStatesStartingWith(term).pipe(
            catchError(() => of([])), // empty list on error
            // map(cities => cities.map(city => city.city)), // transform the list of objects to a list of city names
            tap(() => (this.cityLoading = false)),
          ),
        ),
      ),
    );
  }
  trackByFn(item: GeoResult) {
    return item.id;
  }
  setCityOrState(cityOrState: CityAndStateResult) {
    if (cityOrState) {
      if (cityOrState.type === 'state') {
        this.criteria.state = cityOrState.state;
      } else {
        this.criteria.city = cityOrState.name;
        this.criteria.state = cityOrState.state;
        this.criteria.searchType = 'radius';
        this.criteria.radius = 20;
      }
    } else {
      this.criteria.state = null;
      this.criteria.city = null;
      this.criteria.radius = null;
      this.criteria.searchType = 'exact';
    }
  }
  getTypes() {
    if (this.criteria.criteriaType === 'business') {
      return this.selectOptions.typesOfBusiness;
    } else if (this.criteria.criteriaType === 'commercialProperty') {
      return this.selectOptions.typesOfCommercialProperty;
    } else {
      return this.selectOptions.customerSubTypes;
    }
  }
  getPlaceholderLabel() {
    if (this.criteria.criteriaType === 'business') {
      return 'Business Type';
    } else if (this.criteria.criteriaType === 'commercialProperty') {
      return 'Property Type';
    } else {
      return 'Professional Type';
    }
  }
  setTotalNumberOfResults() {
    if (this.criteria) {
      console.log(`Getting total number of results for ${this.criteria.criteriaType}`);
      if (this.criteria.criteriaType === 'business' || this.criteria.criteriaType === 'commercialProperty') {
        this.numberOfResults$ = this.listingService.getNumberOfListings(this.criteria, this.criteria.criteriaType);
      } else if (this.criteria.criteriaType === 'broker') {
        this.numberOfResults$ = this.userService.getNumberOfBroker(this.criteria);
      } else {
        this.numberOfResults$ = of();
      }
    }
  }
  getNumberOfFiltersSet() {
    if (this.criteria?.criteriaType === 'broker') {
      return compareObjects(createEmptyUserListingCriteria(), this.criteria, ['start', 'length', 'page', 'searchType', 'radius']);
    } else if (this.criteria?.criteriaType === 'business') {
      return compareObjects(createEmptyBusinessListingCriteria(), this.criteria, ['start', 'length', 'page', 'searchType', 'radius']);
    } else if (this.criteria?.criteriaType === 'commercialProperty') {
      return compareObjects(createEmptyCommercialPropertyListingCriteria(), this.criteria, ['start', 'length', 'page', 'searchType', 'radius']);
    } else {
      return 0;
    }
  }
}
