import {
  Component,
  ElementRef,
  ViewChild,
  Inject,
  PLATFORM_ID,
  AfterViewInit,
  ChangeDetectorRef
} from '@angular/core';
import { isPlatformBrowser, CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HttpClient, HttpParams } from '@angular/common/http';
import { CustomSelectComponent } from '../../components/custom-select/custom-select';
import { environment } from '../../../environments/environment';

type TrocaKey = 'item' | 'linhaAntiga' | 'linhaNova' | 'iccid' | 'dataTroca' | 'motivo' | 'observacao';

interface TrocaRow {
  id: string;
  item: string;
  linhaAntiga: string;
  linhaNova: string;
  iccid: string;
  dataTroca: string;
  motivo: string;
  observacao: string;
  raw: any;
}

interface ApiPagedResult<T> {
  page?: number;
  pageSize?: number;
  total?: number;
  items?: T[];
}

interface GroupItem {
  key: string;      // aqui é o MOTIVO
  total: number;
  trocas: number;
  comIccid: number;
  semIccid: number;
}

/** ✅ DTO da linha do GERAL (para selects) */
interface LineOptionDto {
  id: string;
  item: number;
  linha: string | null;
  chip: string | null;
  cliente: string | null;
  usuario: string | null;
  skil: string | null;
  label?: string;
}

@Component({
  standalone: true,
  imports: [CommonModule, FormsModule, CustomSelectComponent],
  templateUrl: './troca-numero.html',
  styleUrls: ['./troca-numero.scss']
})
export class TrocaNumero implements AfterViewInit {
  toastMessage = '';
  loading = false;

  @ViewChild('successToast', { static: false }) successToast!: ElementRef;

  constructor(
    @Inject(PLATFORM_ID) private platformId: object,
    private http: HttpClient,
    private cdr: ChangeDetectorRef
  ) {}

  private readonly apiBase = (() => {
    const raw = (environment.apiUrl || '').replace(/\/+$/, '');
    const apiBase = raw.toLowerCase().endsWith('/api') ? raw : `${raw}/api`;
    return `${apiBase}/trocanumero`;
  })();

  /** ✅ base do GERAL (para buscar clientes/linhas no modal) */
  private readonly linesApiBase = (() => {
    const raw = (environment.apiUrl || '').replace(/\/+$/, '');
    const apiBase = raw.toLowerCase().endsWith('/api') ? raw : `${raw}/api`;
    return `${apiBase}/lines`;
  })();

  // ====== DATA ======
  groups: GroupItem[] = [];
  pagedGroups: GroupItem[] = [];
  expandedGroup: string | null = null;
  groupRows: TrocaRow[] = [];

  private rowsByKey = new Map<string, TrocaRow[]>();

  // KPIs
  groupLoadedRecords = 0;
  groupTotalTrocas = 0;
  groupTotalIccids = 0;

  // ====== FILTERS & PAGINATION ======
  searchTerm = '';
  private searchTimer: any = null;
  page = 1;
  pageSize = 10;
  pageSizeOptions = [10, 20, 50, 100];
  total = 0;

  // ====== EDIT MODAL ======
  editOpen = false;
  editSaving = false;
  editModel: any = null;

  // ====== CREATE MODAL ======
  createOpen = false;
  createSaving = false;
  createModel: any = {
    item: '',
    linhaAntiga: '',
    linhaNova: '',
    iccid: '',
    dataTroca: '',
    motivo: '',
    observacao: ''
  };

  /** ✅ selects do GERAL no modal */
  clientsFromGeral: string[] = [];
  linesFromClient: LineOptionDto[] = [];
  selectedCliente: string = '';
  selectedLineId: string = '';
  loadingClients = false;
  loadingLines = false;

  async ngAfterViewInit() {
    if (!isPlatformBrowser(this.platformId)) return;
    this.initAnimations();
    setTimeout(() => this.refresh());
  }

  private initAnimations() {
    document.documentElement.classList.add('js-animate');
    setTimeout(() => {
      const items = document.querySelectorAll<HTMLElement>('[data-animate]');
      items.forEach((el) => el.classList.add('is-visible'));
    }, 100);
  }

  refresh() {
    this.page = 1;
    this.loadForGroups();
  }

  onSearch() {
    if (this.searchTimer) clearTimeout(this.searchTimer);
    this.searchTimer = setTimeout(() => {
      this.page = 1;
      this.expandedGroup = null;
      this.groupRows = [];
      this.loadForGroups();
    }, 300);
  }

  clearSearch() {
    this.searchTerm = '';
    this.page = 1;
    this.expandedGroup = null;
    this.groupRows = [];
    this.loadForGroups();
  }

  onPageSizeChange() {
    this.page = 1;
    this.applyPagination();
  }

  goToPage(p: number) {
    this.page = Math.max(1, Math.min(this.totalPages, p));
    this.applyPagination();
  }

  get totalPages() { return Math.ceil((this.total || 0) / this.pageSize) || 1; }

  get pageNumbers() {
    const total = this.totalPages;
    const current = this.page;
    const max = 5;
    let start = Math.max(1, current - 2);
    let end = Math.min(total, start + (max - 1));
    start = Math.max(1, end - (max - 1));

    const pages: number[] = [];
    for (let i = start; i <= end; i++) pages.push(i);
    return pages;
  }

  get pageStart() { return this.total === 0 ? 0 : (this.page - 1) * this.pageSize + 1; }
  get pageEnd() {
    if (this.total === 0) return 0;
    return Math.min(this.page * this.pageSize, this.total);
  }

  trackById(_: number, row: TrocaRow) { return row.id; }

  // =======================================================================
  // LOAD LOGIC (igual MUREG: puxa bastante e agrupa no front)
  // =======================================================================
  private loadForGroups() {
    this.loading = true;
    const MAX_FETCH = 5000;

    let params = new HttpParams()
      .set('page', '1')
      .set('pageSize', String(MAX_FETCH))
      .set('search', (this.searchTerm ?? '').trim())
      .set('sortBy', 'motivo')
      .set('sortDir', 'asc');

    this.http.get<ApiPagedResult<any> | any[]>(this.apiBase, { params }).subscribe({
      next: (res: any) => {
        const items = Array.isArray(res) ? res : (res.items ?? []);
        const normalized = (items ?? []).map((x: any, idx: number) => this.normalizeRow(x, idx));
        this.buildGroups(normalized);
        this.applyPagination();
        this.loading = false;
        this.cdr.detectChanges();
      },
      error: async () => {
        this.loading = false;
        await this.showToast('Erro ao carregar Troca de Número.');
      }
    });
  }

  private buildGroups(all: TrocaRow[]) {
    this.rowsByKey.clear();

    const safeKey = (v: any) => (String(v ?? '').trim() || 'SEM MOTIVO');

    for (const r of all) {
      const key = safeKey(r.motivo);
      r.motivo = key;
      const arr = this.rowsByKey.get(key) ?? [];
      arr.push(r);
      this.rowsByKey.set(key, arr);
    }

    const groups: GroupItem[] = [];
    let trocasTotal = 0;
    let iccidsTotal = 0;

    this.rowsByKey.forEach((arr, key) => {
      const total = arr.length;
      const trocas = arr.filter(x => this.isTroca(x)).length;
      const comIccid = arr.filter(x => String(x.iccid ?? '').trim() !== '').length;
      const semIccid = total - comIccid;

      trocasTotal += trocas;
      iccidsTotal += comIccid;

      groups.push({ key, total, trocas, comIccid, semIccid });
    });

    groups.sort((a, b) => a.key.localeCompare(b.key, 'pt-BR', { sensitivity: 'base' }));

    this.groups = groups;
    this.total = groups.length;
    this.groupLoadedRecords = all.length;
    this.groupTotalTrocas = trocasTotal;
    this.groupTotalIccids = iccidsTotal;
  }

  private applyPagination() {
    const start = (this.page - 1) * this.pageSize;
    const end = start + this.pageSize;
    this.pagedGroups = this.groups.slice(start, end);

    if (this.expandedGroup && !this.pagedGroups.some(g => g.key === this.expandedGroup)) {
      this.expandedGroup = null;
      this.groupRows = [];
    }
  }

  toggleGroup(key: string) {
    if (this.expandedGroup === key) {
      this.expandedGroup = null;
      this.groupRows = [];
      return;
    }

    this.expandedGroup = key;
    const rows = this.rowsByKey.get(key) ?? [];
    this.groupRows = [...rows].sort((a, b) => {
      const ai = parseInt(String(a.item ?? '0'), 10);
      const bi = parseInt(String(b.item ?? '0'), 10);
      if (Number.isFinite(ai) && Number.isFinite(bi) && ai !== bi) return ai - bi;
      return String(a.linhaNova ?? '').localeCompare(String(b.linhaNova ?? ''), 'pt-BR', { sensitivity: 'base' });
    });
  }

  isTroca(r: TrocaRow): boolean {
    const a = String(r.linhaAntiga ?? '').trim();
    const b = String(r.linhaNova ?? '').trim();
    if (!a || !b) return false;
    return a !== b;
  }

  private normalizeRow(x: any, idx: number): TrocaRow {
    const pick = (obj: any, keys: string[]): any => {
      for (const k of keys) {
        if (obj && obj[k] !== undefined && obj[k] !== null && String(obj[k]).trim() !== '') return obj[k];
      }
      return '';
    };

    const item = pick(x, ['item', 'ITEM', 'ITÉM']);
    const linhaAntiga = pick(x, ['linhaAntiga', 'linha_antiga', 'LINHA ANTIGA']);
    const linhaNova = pick(x, ['linhaNova', 'linha_nova', 'LINHA NOVA']);
    const iccid = pick(x, ['iccid', 'ICCID']);
    const dataTroca = pick(x, ['dataTroca', 'data_troca', 'DATA TROCA', 'DATA DA TROCA']);
    const motivo = pick(x, ['motivo', 'MOTIVO']);
    const observacao = pick(x, ['observacao', 'OBSERVAÇÃO', 'OBSERVACAO']);

    const id = String(pick(x, ['id', 'ID']) || `${idx}-${item}-${linhaNova}-${iccid}`);

    return {
      id,
      item: String(item ?? ''),
      linhaAntiga: String(linhaAntiga ?? ''),
      linhaNova: String(linhaNova ?? ''),
      iccid: String(iccid ?? ''),
      dataTroca: String(dataTroca ?? ''),
      motivo: String(motivo ?? ''),
      observacao: String(observacao ?? ''),
      raw: x
    };
  }

  // =======================================================================
  // ✅ GERAL -> selects do modal (Clientes / Linhas do cliente)
  // =======================================================================
  private loadClientsFromGeral() {
    this.loadingClients = true;

    this.http.get<string[]>(`${this.linesApiBase}/clients`).subscribe({
      next: (res) => {
        this.clientsFromGeral = (res ?? []).filter(x => !!String(x ?? '').trim());
        this.loadingClients = false;
        this.cdr.detectChanges();
      },
      error: async () => {
        this.loadingClients = false;
        await this.showToast('Erro ao carregar clientes do GERAL.');
      }
    });
  }

  private loadLinesByClient(cliente: string) {
    const c = String(cliente ?? '').trim();
    if (!c) {
      this.linesFromClient = [];
      this.selectedLineId = '';
      return;
    }

    this.loadingLines = true;

    const params = new HttpParams().set('cliente', c);

    this.http.get<LineOptionDto[]>(`${this.linesApiBase}/by-client`, { params }).subscribe({
      next: (res) => {
        this.linesFromClient = (res ?? []).map((x) => ({
          ...x,
          label: `${x.item ?? ''} • ${x.linha ?? '-'} • ${x.usuario ?? 'SEM USUÁRIO'}`
        }));
        this.loadingLines = false;
        this.cdr.detectChanges();
      },
      error: async () => {
        this.loadingLines = false;
        await this.showToast('Erro ao carregar linhas do cliente (GERAL).');
      }
    });
  }

  onClienteChange() {
    // reset quando troca cliente
    this.selectedLineId = '';
    this.linesFromClient = [];

    // limpa campos auto
    this.createModel.linhaAntiga = '';
    this.createModel.iccid = '';

    this.loadLinesByClient(this.selectedCliente);
  }

  onLineChange() {
    const id = String(this.selectedLineId ?? '').trim();
    const found = this.linesFromClient.find(x => x.id === id);

    // preenche automaticamente a partir do GERAL
    this.createModel.linhaAntiga = found?.linha ?? '';
    this.createModel.iccid = found?.chip ?? ''; // Chip do GERAL => ICCID aqui

    // se quiser, pode setar item automaticamente também:
    if (found?.item !== undefined && found?.item !== null) {
      // só seta se estiver vazio (pra não atrapalhar quem quiser digitar)
      if (!String(this.createModel.item ?? '').trim()) {
        this.createModel.item = String(found.item);
      }
    }
  }

  // ====== MODAL EDIÇÃO ======
  onEditar(r: TrocaRow) {
    this.editOpen = true;
    this.editSaving = false;

    this.editModel = {
      id: r.id,
      item: r.item,
      linhaAntiga: r.linhaAntiga,
      linhaNova: r.linhaNova,
      iccid: r.iccid,
      motivo: r.motivo,
      observacao: r.observacao,
      dataTroca: this.isoToDateInput(r.dataTroca)
    };
  }

  closeEdit() {
    this.editOpen = false;
    this.editModel = null;
    this.editSaving = false;
  }

  saveEdit() {
    if (!this.editModel || !this.editModel.id) return;
    this.editSaving = true;

    const payload = {
      item: this.toNumberOrNull(this.editModel.item),
      linhaAntiga: this.editModel.linhaAntiga,
      linhaNova: this.editModel.linhaNova,
      iccid: this.editModel.iccid,
      motivo: this.editModel.motivo,
      observacao: this.editModel.observacao,
      dataTroca: this.dateInputToIso(this.editModel.dataTroca)
    };

    this.http.put(`${this.apiBase}/${this.editModel.id}`, payload).subscribe({
      next: async () => {
        this.editSaving = false;
        await this.showToast('Registro atualizado com sucesso!');
        this.closeEdit();
        const currentGroup = this.expandedGroup;
        this.loadForGroups();
        if (currentGroup) setTimeout(() => this.expandedGroup = currentGroup, 350);
      },
      error: async () => {
        this.editSaving = false;
        await this.showToast('Erro ao salvar edição.');
      }
    });
  }

  // ====== MODAL CRIAÇÃO ======
  onCreate() {
    this.createOpen = true;
    this.createSaving = false;

    // reset do form
    this.createModel = {
      item: '',
      linhaAntiga: '',
      linhaNova: '',
      iccid: '',
      dataTroca: '',
      motivo: '',
      observacao: ''
    };

    // reset dos selects
    this.selectedCliente = '';
    this.selectedLineId = '';
    this.clientsFromGeral = [];
    this.linesFromClient = [];

    // carrega clientes do GERAL
    this.loadClientsFromGeral();
  }

  closeCreate() {
    this.createOpen = false;
  }

  saveCreate() {
    // ✅ validações do "beber do GERAL"
    if (!String(this.selectedCliente ?? '').trim()) {
      this.showToast('Selecione um Cliente do GERAL.');
      return;
    }
    if (!String(this.selectedLineId ?? '').trim()) {
      this.showToast('Selecione uma Linha do Cliente (GERAL).');
      return;
    }
    if (!String(this.createModel.linhaNova ?? '').trim()) {
      this.showToast('Informe a Linha Nova.');
      return;
    }

    this.createSaving = true;

    const payload = {
      item: this.toNumberOrNull(this.createModel.item),
      linhaAntiga: this.createModel.linhaAntiga, // auto do GERAL
      linhaNova: this.createModel.linhaNova,
      iccid: this.createModel.iccid, // auto do GERAL
      motivo: this.createModel.motivo,
      observacao: this.createModel.observacao,
      dataTroca: this.dateInputToIso(this.createModel.dataTroca)
    };

    this.http.post(this.apiBase, payload).subscribe({
      next: async () => {
        this.createSaving = false;
        await this.showToast('Troca criada com sucesso!');
        this.closeCreate();
        this.loadForGroups();
      },
      error: async () => {
        this.createSaving = false;
        await this.showToast('Erro ao criar Troca.');
      }
    });
  }

  // Helpers
  private toNumberOrNull(v: any): number | null {
    const n = parseInt(String(v ?? '').trim(), 10);
    return Number.isFinite(n) ? n : null;
  }

  private isoToDateInput(iso: string | null | undefined): string {
    if (!iso) return '';
    const dt = new Date(iso);
    if (Number.isNaN(dt.getTime())) return '';
    return dt.toISOString().slice(0, 10);
  }

  private dateInputToIso(val: string | null | undefined): string | null {
    if (!val) return null;
    const dt = new Date(val);
    if (Number.isNaN(dt.getTime())) return null;
    return dt.toISOString();
  }

  displayValue(key: TrocaKey, v: any): string {
    if (v === null || v === undefined || String(v).trim() === '') return '-';

    if (key === 'dataTroca') {
      const s = String(v).trim();
      const d = new Date(s);
      if (!Number.isNaN(d.getTime())) return new Intl.DateTimeFormat('pt-BR').format(d);
      return s;
    }
    return String(v);
  }

  private async showToast(message: string) {
    if (!isPlatformBrowser(this.platformId)) return;
    this.toastMessage = message;
    this.cdr.detectChanges();

    if (!this.successToast?.nativeElement) return;

    try {
      const bs = await import('bootstrap');
      const toastInstance = bs.Toast.getOrCreateInstance(this.successToast.nativeElement, {
        autohide: true,
        delay: 3000
      });
      toastInstance.show();
    } catch (error) {
      console.error(error);
    }
  }
}
