import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatBadgeModule } from '@angular/material/badge';
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatChipsModule } from '@angular/material/chips';
import { MatDividerModule } from '@angular/material/divider';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table';
import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { forkJoin } from 'rxjs';

import { ApiService } from './api.service';

type ViewId = 'dashboard' | 'tickets' | 'search' | 'users';
type SearchMode = 'text' | 'ticket';

interface NavItem {
  id: ViewId;
  label: string;
  icon: string;
}

interface TaxonomyOption {
  id: number;
  label: string;
}

@Component({
  selector: 'ticket-root',
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    MatBadgeModule,
    MatButtonModule,
    MatButtonToggleModule,
    MatCardModule,
    MatCheckboxModule,
    MatChipsModule,
    MatDividerModule,
    MatExpansionModule,
    MatFormFieldModule,
    MatIconModule,
    MatInputModule,
    MatListModule,
    MatProgressSpinnerModule,
    MatSelectModule,
    MatSidenavModule,
    MatSlideToggleModule,
    MatSnackBarModule,
    MatTableModule,
    MatTabsModule,
    MatToolbarModule,
    MatTooltipModule
  ],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  readonly navItems: NavItem[] = [
    { id: 'dashboard', label: 'Dashboard', icon: 'dashboard' },
    { id: 'tickets', label: 'Tickets', icon: 'confirmation_number' },
    { id: 'search', label: 'AI search', icon: 'manage_search' },
    { id: 'users', label: 'Users', icon: 'group' }
  ];

  readonly ticketColumns = ['ticket', 'client', 'subject', 'product', 'status', 'opened', 'actions'];
  readonly userColumns = ['tid', 'name', 'status', 'filters', 'notifications', 'actions'];

  authChecked = true;
  user: any = null;
  loginForm = { username: 'admin', password: '' };
  loginLoading = false;
  appError = '';

  activeView: ViewId = 'dashboard';
  dashboardData: any = null;
  dashboardLoading = false;
  dashboardError = '';

  ticketFilters: Record<string, any> = {
    q: '',
    date_from: '',
    date_to: '',
    product_id: '',
    competence_id: '',
    area_id: '',
    subarea_id: '',
    status_id: '',
    client_id: ''
  };
  tickets: any[] = [];
  ticketLoading = false;
  ticketsError = '';
  ticketOffset = 0;
  ticketHasMore = false;
  selectedTicket: any = null;
  selectedTicketLoading = false;
  selectedTicketError = '';

  searchMode: SearchMode = 'text';
  searchTextValue = '';
  searchTicketId: number | null = null;
  searchFilters: Record<string, any> = {
    product_id: '',
    competence_id: '',
    area_id: '',
    subarea_id: '',
    client_id: '',
    recent_months: '',
    min_confidence: '',
    require_code_match: false
  };
  searchResults: any[] = [];
  searchLoading = false;
  searchError = '';
  searchOffset = 0;
  searchHasMore = false;
  searchLimit = 8;

  users: any[] = [];
  usersLoading = false;
  usersError = '';
  userQuery = '';
  userStatus = '';
  selectedUser: any = null;
  selectedUserFilters: any[] = [];
  selectedUserSettings: any = null;
  userDetailLoading = false;
  userDetailError = '';
  filterDraft = { sort: 'C', sort_value: '' };
  taxonomyLoading = false;
  taxonomyLoaded = false;
  taxonomyError = '';

  taxonomy: Record<string, TaxonomyOption[]> = {
    products: [],
    competences: [],
    areas: [],
    subareas: [],
    statuses: []
  };

  constructor(
    private readonly api: ApiService,
    private readonly snack: MatSnackBar
  ) {}

  ngOnInit(): void {
    this.api.me().subscribe({
      next: (response) => {
        this.user = response.user;
        if (this.user) {
          this.bootstrapAppData();
        }
      },
      error: () => {
        this.user = null;
      }
    });
  }

  login(): void {
    if (!this.loginForm.username || !this.loginForm.password) {
      this.showMessage('Username and password are required');
      return;
    }
    this.loginLoading = true;
    this.api.login(this.loginForm.username, this.loginForm.password).subscribe({
      next: (response) => {
        this.loginLoading = false;
        this.user = response.user;
        this.loginForm.password = '';
        this.bootstrapAppData();
      },
      error: (error) => {
        this.loginLoading = false;
        this.showError(error, 'Login failed');
      }
    });
  }

  logout(): void {
    this.api.logout().subscribe({
      next: () => this.resetSession(),
      error: () => this.resetSession()
    });
  }

  setView(view: ViewId): void {
    this.activeView = view;
    if (view === 'dashboard') {
      this.loadDashboard();
    }
    if (view === 'tickets') {
      this.loadTaxonomy();
    }
    if (view === 'tickets' && this.tickets.length === 0 && !this.ticketLoading) {
      this.loadTickets(true);
    }
    if (view === 'search') {
      this.loadTaxonomy();
    }
    if (view === 'users') {
      this.loadTaxonomy();
    }
    if (view === 'users' && this.users.length === 0 && !this.usersLoading) {
      this.loadUsers();
    }
  }

  refreshActive(): void {
    if (this.activeView === 'dashboard') {
      this.loadDashboard();
    }
    if (this.activeView === 'tickets') {
      this.loadTickets(true);
    }
    if (this.activeView === 'users') {
      this.loadUsers();
    }
    if (this.activeView === 'search' && (this.searchTextValue.trim() || this.searchTicketId)) {
      this.runSearch(true);
    }
  }

  bootstrapAppData(): void {
    this.appError = '';
    this.activeView = 'dashboard';
    this.loadDashboard();
    this.loadTaxonomy(true);
    this.loadTickets(true);
    this.loadUsers();
  }

  loadDashboard(): void {
    if (!this.user) {
      return;
    }
    this.dashboardLoading = true;
    this.dashboardError = '';
    this.api.dashboard().subscribe({
      next: (response) => {
        this.dashboardData = response;
        this.dashboardLoading = false;
      },
      error: (error) => {
        this.dashboardLoading = false;
        this.dashboardError = this.errorText(error, 'Dashboard could not be loaded');
        this.showError(error, 'Dashboard could not be loaded');
      }
    });
  }

  loadTickets(reset: boolean): void {
    if (this.ticketLoading && !reset) {
      return;
    }
    if (reset) {
      this.ticketOffset = 0;
      this.tickets = [];
    }
    this.ticketLoading = true;
    this.ticketsError = '';
    const params = this.cleanParams({
      ...this.ticketFilters,
      limit: 50,
      offset: this.ticketOffset
    });
    this.api.tickets(params).subscribe({
      next: (response) => {
        const items = response.items || [];
        this.tickets = reset ? items : [...this.tickets, ...items];
        this.ticketHasMore = !!response.has_more;
        this.ticketOffset = Number(response.offset || 0) + items.length;
        this.ticketLoading = false;
      },
      error: (error) => {
        this.ticketLoading = false;
        this.ticketsError = this.errorText(error, 'Tickets could not be loaded');
        this.showError(error, 'Tickets could not be loaded');
      }
    });
  }

  openTicket(ticketId: number): void {
    this.selectedTicketLoading = true;
    this.selectedTicket = null;
    this.selectedTicketError = '';
    this.api.ticket(ticketId).subscribe({
      next: (response) => {
        this.selectedTicket = response.ticket;
        this.selectedTicketLoading = false;
      },
      error: (error) => {
        this.selectedTicketLoading = false;
        this.selectedTicketError = this.errorText(error, 'Ticket detail could not be loaded');
        this.showError(error, 'Ticket detail could not be loaded');
      }
    });
  }

  searchFromTicket(ticketId: number): void {
    this.searchMode = 'ticket';
    this.searchTicketId = ticketId;
    this.setView('search');
    this.runSearch(true);
  }

  runSearch(reset: boolean): void {
    if (this.searchLoading) {
      return;
    }
    if (reset) {
      this.searchOffset = 0;
      this.searchResults = [];
    }
    this.searchError = '';
    const params = this.cleanParams({
      ...this.searchFilters,
      limit: this.searchLimit,
      offset: this.searchOffset
    });
    if (!params['require_code_match']) {
      delete params['require_code_match'];
    }

    if (this.searchMode === 'text') {
      const query = this.searchTextValue.trim();
      if (query.length < 2) {
        this.showMessage('Enter at least two characters to search');
        return;
      }
      params['q'] = query;
      this.searchLoading = true;
      this.api.searchText(params).subscribe({
        next: (response) => this.applySearchResponse(response, reset),
        error: (error) => {
          this.searchLoading = false;
          this.searchError = this.errorText(error, 'Search failed');
          this.showError(error, 'Search failed');
        }
      });
      return;
    }

    const ticketId = Number(this.searchTicketId);
    if (!ticketId) {
      this.showMessage('Enter a ticket number');
      return;
    }
    this.searchLoading = true;
    this.api.searchTicket(ticketId, params).subscribe({
      next: (response) => this.applySearchResponse(response, reset),
      error: (error) => {
        this.searchLoading = false;
        this.searchError = this.errorText(error, 'Search failed');
        this.showError(error, 'Search failed');
      }
    });
  }

  applySearchResponse(response: any, reset: boolean): void {
    const items = response.items || [];
    this.searchResults = reset ? items : [...this.searchResults, ...items];
    this.searchHasMore = items.length === this.searchLimit;
    this.searchOffset = Number(response.offset || 0) + items.length;
    this.searchLoading = false;
  }

  markFeedback(result: any, feedback: 'useful' | 'not_useful' | 'favorite'): void {
    const payload: any = {
      suggested_ticket_id: Number(result.ticket_id),
      feedback
    };
    if (this.searchMode === 'ticket' && this.searchTicketId) {
      payload.query_ticket_id = Number(this.searchTicketId);
    }
    if (feedback !== 'favorite' && !payload.query_ticket_id) {
      this.showMessage('Useful feedback needs a source ticket search');
      return;
    }
    this.api.feedback(payload).subscribe({
      next: () => {
        result.feedback_state = feedback;
        this.showMessage(feedback === 'favorite' ? 'Favorite saved' : 'Feedback saved');
      },
      error: (error) => this.showError(error, 'Feedback could not be saved')
    });
  }

  loadUsers(): void {
    if (this.usersLoading) {
      return;
    }
    this.usersLoading = true;
    this.usersError = '';
    this.api.users(this.cleanParams({ q: this.userQuery, status: this.userStatus })).subscribe({
      next: (response) => {
        this.users = response.items || [];
        this.usersLoading = false;
        if (this.selectedUser) {
          const updated = this.users.find((item) => item.tid === this.selectedUser.tid);
          this.selectedUser = updated || this.selectedUser;
        }
      },
      error: (error) => {
        this.usersLoading = false;
        this.usersError = this.errorText(error, 'Users could not be loaded');
        this.showError(error, 'Users could not be loaded');
      }
    });
  }

  selectUser(user: any): void {
    this.selectedUser = user;
    this.userDetailLoading = true;
    this.userDetailError = '';
    this.api.userFilters(user.tid).subscribe({
      next: (response) => {
        this.selectedUserFilters = response.items || [];
        this.userDetailLoading = false;
      },
      error: (error) => {
        this.userDetailLoading = false;
        this.userDetailError = this.errorText(error, 'Filters could not be loaded');
        this.showError(error, 'Filters could not be loaded');
      }
    });
    this.api.userSettings(user.tid).subscribe({
      next: (response) => {
        this.selectedUserSettings = response.settings;
      },
      error: (error) => {
        this.userDetailError = this.errorText(error, 'Settings could not be loaded');
        this.showError(error, 'Settings could not be loaded');
      }
    });
  }

  approveUser(user: any): void {
    this.api.updateUser(user.tid, { status: 'A' }).subscribe({
      next: (response) => {
        Object.assign(user, response.user);
        this.showMessage('User approved');
        this.loadUsers();
      },
      error: (error) => this.showError(error, 'User could not be approved')
    });
  }

  toggleAdmin(user: any): void {
    this.api.updateUser(user.tid, { user_admin: !user.user_admin }).subscribe({
      next: (response) => {
        Object.assign(user, response.user);
        this.showMessage(user.user_admin ? 'Admin enabled' : 'Admin disabled');
      },
      error: (error) => this.showError(error, 'Admin flag could not be changed')
    });
  }

  addFilter(): void {
    if (!this.selectedUser || !this.filterDraft.sort_value) {
      this.showMessage('Choose a user and a filter value');
      return;
    }
    this.api.addUserFilter(this.selectedUser.tid, this.filterDraft).subscribe({
      next: () => {
        this.filterDraft.sort_value = '';
        this.selectUser(this.selectedUser);
        this.showMessage('Filter saved');
      },
      error: (error) => this.showError(error, 'Filter could not be saved')
    });
  }

  deleteFilter(filter: any): void {
    if (!this.selectedUser) {
      return;
    }
    this.api.deleteUserFilter(this.selectedUser.tid, filter.fid).subscribe({
      next: () => {
        this.selectedUserFilters = this.selectedUserFilters.filter((item) => item.fid !== filter.fid);
        this.showMessage('Filter removed');
        this.loadUsers();
      },
      error: (error) => this.showError(error, 'Filter could not be removed')
    });
  }

  saveSettings(): void {
    if (!this.selectedUser || !this.selectedUserSettings) {
      return;
    }
    const settings = this.selectedUserSettings;
    const patch = {
      notifications_enabled: !!settings.notifications_enabled,
      quiet_start_hour: this.emptyToNull(settings.quiet_start_hour),
      quiet_end_hour: this.emptyToNull(settings.quiet_end_hour),
      digest_minutes: Number(settings.digest_minutes || 0),
      high_gravity_only: !!settings.high_gravity_only
    };
    this.api.updateUserSettings(this.selectedUser.tid, patch).subscribe({
      next: (response) => {
        this.selectedUserSettings = response.settings;
        this.showMessage('Notification settings saved');
        this.loadUsers();
      },
      error: (error) => this.showError(error, 'Settings could not be saved')
    });
  }

  clearQuietHours(): void {
    if (!this.selectedUserSettings) {
      return;
    }
    this.selectedUserSettings.quiet_start_hour = null;
    this.selectedUserSettings.quiet_end_hour = null;
  }

  onFilterSortChange(): void {
    this.filterDraft.sort_value = '';
  }

  filterOptions(sort: string): TaxonomyOption[] {
    if (sort === 'P') {
      return this.taxonomy['products'];
    }
    if (sort === 'C') {
      return this.taxonomy['competences'];
    }
    if (sort === 'A') {
      return this.taxonomy['areas'];
    }
    if (sort === 'S') {
      return this.taxonomy['subareas'];
    }
    return [];
  }

  loadTaxonomy(force = false): void {
    if (this.taxonomyLoading || (this.taxonomyLoaded && !force)) {
      return;
    }
    this.taxonomyLoading = true;
    this.taxonomyError = '';
    forkJoin({
      products: this.api.taxonomy('products', { limit: 400 }),
      competences: this.api.taxonomy('competences', { limit: 400 }),
      areas: this.api.taxonomy('areas', { limit: 400 }),
      subareas: this.api.taxonomy('subareas', { limit: 600 }),
      statuses: this.api.taxonomy('statuses', { limit: 400 })
    }).subscribe({
      next: (response: any) => {
        this.taxonomy.products = response.products?.items || [];
        this.taxonomy.competences = response.competences?.items || [];
        this.taxonomy.areas = response.areas?.items || [];
        this.taxonomy.subareas = response.subareas?.items || [];
        this.taxonomy.statuses = response.statuses?.items || [];
        this.taxonomyLoaded = true;
        this.taxonomyLoading = false;
      },
      error: (error) => {
        this.taxonomyLoading = false;
        this.taxonomyLoaded = false;
        this.taxonomyError = this.errorText(error, 'Filter lists could not be loaded');
        this.showError(error, 'Filter lists could not be loaded');
      }
    });
  }

  resetTicketFilters(): void {
    Object.keys(this.ticketFilters).forEach((key) => {
      this.ticketFilters[key] = '';
    });
    this.loadTickets(true);
  }

  resetSearchFilters(): void {
    Object.keys(this.searchFilters).forEach((key) => {
      this.searchFilters[key] = key === 'require_code_match' ? false : '';
    });
  }

  textInputValue(event: Event): string {
    return (event.target as HTMLInputElement | null)?.value || '';
  }

  numberInputValue(event: Event): number | null {
    const value = (event.target as HTMLInputElement | null)?.value || '';
    return value ? Number(value) : null;
  }

  shortText(value: unknown, limit = 150): string {
    const text = String(value || '').trim();
    if (text.length <= limit) {
      return text;
    }
    return `${text.slice(0, limit).trim()}...`;
  }

  trackByTicket(_: number, item: any): number {
    return Number(item.ticket_id);
  }

  trackByUser(_: number, item: any): number {
    return Number(item.tid);
  }

  trackByFilter(_: number, item: any): number {
    return Number(item.fid);
  }

  private cleanParams(params: Record<string, any>): Record<string, any> {
    const clean: Record<string, any> = {};
    Object.entries(params).forEach(([key, value]) => {
      if (value === null || value === undefined || value === '') {
        return;
      }
      clean[key] = value;
    });
    return clean;
  }

  private emptyToNull(value: any): number | null {
    if (value === '' || value === null || value === undefined) {
      return null;
    }
    return Number(value);
  }

  private showMessage(message: string): void {
    this.snack.open(message, 'Close', { duration: 3500 });
  }

  private showError(error: any, fallback: string): void {
    const detail = this.errorText(error, fallback);
    this.appError = detail;
    this.snack.open(String(detail), 'Close', { duration: 6000 });
  }

  private errorText(error: any, fallback: string): string {
    return String(error?.error?.detail || error?.message || fallback);
  }

  private resetSession(): void {
    this.user = null;
    this.dashboardData = null;
    this.tickets = [];
    this.searchResults = [];
    this.users = [];
    this.selectedUser = null;
    this.selectedTicket = null;
  }
}
