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 { LinesService } from '../../services/lines.service';
import { CustomSelectComponent } from '../../components/custom-select/custom-select';
import { environment } from '../../../environments/environment';
import { confirmDeletionWithTyping } from '../../utils/destructive-confirmation';

type MuregKey = 'item' | 'linhaAntiga' | 'linhaNova' | 'iccid' | 'dataDaMureg' | 'cliente';

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

interface ClientGroup {
  cliente: string;
  total: number;
  trocas: number;
  comIccid: number;
  semIccid: number;
}

interface MuregRow {
  id: string;
  item: string;
  linhaAntiga: string;
  linhaNova: string;
  iccid: string;
  dataDaMureg: string;
  cliente: string;
  mobileLineId: string;
  raw: any;
}

/** ✅ AGORA COM item/usuario/chip (igual Troca de Número) */
interface LineOptionDto {
  id: string;
  item: number;
  linha: string | null;
  chip: string | null;     // => ICCID
  usuario: string | null;
  cliente?: string | null;
  skil?: string | null;
  label?: string;
}

interface MuregDetailDto {
  id: string;
  item: number;
  linhaAntiga: string | null;
  linhaNova: string | null;
  iccid: string | null;
  dataDaMureg: string | null;
  mobileLineId: string;

  cliente: string | null;
  usuario: string | null;
  skil: string | null;

  linhaAtualNaGeral: string | null;
  chipNaGeral: string | null;
  contaNaGeral: string | null;
  statusNaGeral: string | null;
}

@Component({
  standalone: true,
  imports: [CommonModule, FormsModule, CustomSelectComponent],
  templateUrl: './mureg.html',
  styleUrls: ['./mureg.scss']
})
export class Mureg 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 linesService: LinesService
  ) {}

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

  // ====== DATA ======
  clientGroups: ClientGroup[] = [];
  pagedClientGroups: ClientGroup[] = [];
  expandedGroup: string | null = null;
  groupRows: MuregRow[] = [];
  private rowsByClient = new Map<string, MuregRow[]>();

  // 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;

  // ====== OPTIONS (GERAL) ======
  clientOptions: string[] = [];

  // create options
  lineOptionsCreate: LineOptionDto[] = [];
  createClientsLoading = false;
  createLinesLoading = false;

  // edit options
  lineOptionsEdit: LineOptionDto[] = [];
  editClientsLoading = false;
  editLinesLoading = false;

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

  // ====== DETAIL MODAL ======
  detailOpen = false;
  detailLoading = false;
  detailData: MuregDetailDto | null = null;

  // ====== DELETE MODAL ======
  deleteOpen = false;
  deleteSaving = false;
  deleteTarget: MuregRow | null = null;

  // ====== CREATE MODAL ======
  createOpen = false;
  createSaving = false;
  createModel: any = {
    selectedClient: '',
    mobileLineId: '',
    item: '',
    linhaAntiga: '',
    linhaNova: '',
    iccid: '',
    dataDaMureg: '',
    clienteInfo: ''
  };

  async ngAfterViewInit() {
    if (!isPlatformBrowser(this.platformId)) return;
    this.initAnimations();
    setTimeout(() => {
      this.preloadClients(); // ✅ já deixa o select pronto
      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: MuregRow) { return row.id; }

  // =======================================================================
  // LOAD LOGIC (lista e grupos)
  // =======================================================================
  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', 'cliente')
      .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 MUREG.');
      }
    });
  }

  private buildGroups(all: MuregRow[]) {
    this.rowsByClient.clear();
    const safeClient = (c: any) => (String(c ?? '').trim() || 'SEM CLIENTE');

    for (const r of all) {
      const key = safeClient(r.cliente);
      r.cliente = key;
      const arr = this.rowsByClient.get(key) ?? [];
      arr.push(r);
      this.rowsByClient.set(key, arr);
    }

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

    this.rowsByClient.forEach((arr, cliente) => {
      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({ cliente, total, trocas, comIccid, semIccid });
    });

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

    this.clientGroups = 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.pagedClientGroups = this.clientGroups.slice(start, end);

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

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

    this.expandedGroup = cliente;
    const rows = this.rowsByClient.get(cliente) ?? [];
    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: MuregRow): 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): MuregRow {
    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 dataDaMureg = pick(x, ['dataDaMureg', 'data_da_mureg', 'DATA DA MUREG']);
    const cliente = pick(x, ['cliente', 'CLIENTE']);
    const mobileLineId = String(pick(x, ['mobileLineId', 'MobileLineId', 'mobile_line_id']) ?? '');
    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 ?? ''),
      dataDaMureg: String(dataDaMureg ?? ''),
      cliente: String(cliente ?? ''),
      mobileLineId,
      raw: x
    };
  }

  // =======================================================================
  // CLIENTS / LINES OPTIONS (GERAL)
  // =======================================================================
  private preloadClients() {
    if (this.clientOptions.length > 0) return;

    this.createClientsLoading = true;
    this.editClientsLoading = true;

    this.linesService.getClients().subscribe({
      next: (list) => {
        this.clientOptions = (list ?? []).filter(x => !!String(x ?? '').trim());
        this.createClientsLoading = false;
        this.editClientsLoading = false;
        this.cdr.detectChanges();
      },
      error: async () => {
        this.createClientsLoading = false;
        this.editClientsLoading = false;
        await this.showToast('Erro ao carregar clientes da GERAL.');
      }
    });
  }

  private loadLinesForClient(cliente: string, target: 'create' | 'edit') {
    const c = (cliente ?? '').trim();

    if (!c) {
      if (target === 'create') this.lineOptionsCreate = [];
      else this.lineOptionsEdit = [];
      return;
    }

    if (target === 'create') {
      this.createLinesLoading = true;
      this.lineOptionsCreate = [];
    } else {
      this.editLinesLoading = true;
      this.lineOptionsEdit = [];
    }

    // ✅ aqui assumimos que o getLinesByClient retorna (id,item,linha,chip,usuario...)
    this.linesService.getLinesByClient(c).subscribe({
      next: (items: any[]) => {
        const mapped: LineOptionDto[] = (items ?? [])
          .filter(x => !!String(x?.id ?? '').trim())
          .map(x => ({
            id: String(x.id),
            item: Number(x.item ?? 0),
            linha: x.linha ?? null,
            chip: x.chip ?? null,
            usuario: x.usuario ?? null,
            cliente: x.cliente ?? null,
            skil: x.skil ?? null,
            label: `${x.item ?? ''} • ${x.linha ?? '-'} • ${x.usuario ?? 'SEM USUÁRIO'}`
          }))
          .filter(x => !!String(x.linha ?? '').trim());

        if (target === 'create') {
          this.lineOptionsCreate = mapped;
          this.createLinesLoading = false;
        } else {
          this.lineOptionsEdit = mapped;
          this.editLinesLoading = false;
        }

        this.cdr.detectChanges();
      },
      error: async () => {
        if (target === 'create') this.createLinesLoading = false;
        else this.editLinesLoading = false;

        await this.showToast('Erro ao carregar linhas do cliente (GERAL).');
      }
    });
  }

  private applySelectedLineToModel(model: any, selectedId: string, options: LineOptionDto[]) {
    const id = String(selectedId ?? '').trim();
    const opt = options.find(x => x.id === id);

    if (!opt) return;

    // ✅ snapshot automático (linha antiga)
    model.linhaAntiga = opt.linha ?? '';

    // ✅ ICCID automático (chip do GERAL)
    model.iccid = opt.chip ?? '';

    // ✅ se item estiver vazio, preenche com item da GERAL (igual Troca)
    if (!String(model.item ?? '').trim() && opt.item) {
      model.item = String(opt.item);
    }

    model.clienteInfo = `Vínculo (GERAL): ${model.selectedClient} • ${opt.item} • ${opt.linha ?? '-'} • ${opt.usuario ?? 'SEM USUÁRIO'}`;
  }

  // =======================================================================
  // CREATE MODAL
  // =======================================================================
  onCreate() {
    this.preloadClients();

    this.createOpen = true;
    this.createSaving = false;

    this.createModel = {
      selectedClient: '',
      mobileLineId: '',
      item: '',
      linhaAntiga: '',
      linhaNova: '',
      iccid: '',
      dataDaMureg: '',
      clienteInfo: ''
    };

    this.lineOptionsCreate = [];
  }

  closeCreate() {
    this.createOpen = false;
  }

  onCreateClientChange() {
    const c = (this.createModel.selectedClient ?? '').trim();

    this.createModel.mobileLineId = '';
    this.createModel.linhaAntiga = '';
    this.createModel.iccid = '';
    this.createModel.clienteInfo = c ? `Cliente selecionado: ${c}` : '';

    this.loadLinesForClient(c, 'create');
  }

  onCreateLineChange() {
    this.applySelectedLineToModel(this.createModel, this.createModel.mobileLineId, this.lineOptionsCreate);
  }

  saveCreate() {
    const mobileLineId = String(this.createModel.mobileLineId ?? '').trim();
    const linhaNova = String(this.createModel.linhaNova ?? '').trim();

    if (!mobileLineId || !linhaNova) {
      this.showToast('Selecione Cliente + Linha Antiga (GERAL) e preencha Linha Nova.');
      return;
    }

    this.createSaving = true;

    const payload: any = {
      item: this.toIntOrZero(this.createModel.item),
      mobileLineId,
      linhaAntiga: (this.createModel.linhaAntiga ?? '') || null,
      linhaNova: (this.createModel.linhaNova ?? '') || null,
      iccid: (this.createModel.iccid ?? '') || null,
      dataDaMureg: this.dateInputToIso(this.createModel.dataDaMureg)
    };

    if (!payload.item || payload.item <= 0) delete payload.item;

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

  // =======================================================================
  // EDIT MODAL
  // =======================================================================
  onEditar(r: MuregRow) {
    this.preloadClients();

    this.editOpen = true;
    this.editSaving = false;
    this.editModel = null;
    this.lineOptionsEdit = [];

    this.http.get<MuregDetailDto>(`${this.apiBase}/${r.id}`).subscribe({
      next: (d) => {
        const selectedClient = String(d?.cliente ?? '').trim();

        this.editModel = {
          id: d.id,
          item: String(d.item ?? ''),
          dataDaMureg: this.isoToDateInput(d.dataDaMureg),

          // snapshot atual
          linhaAntiga: String(d.linhaAntiga ?? d.linhaAtualNaGeral ?? ''),
          linhaNova: String(d.linhaNova ?? ''),

          // ✅ se não tiver iccid salvo, usa chip da geral
          iccid: String(d.iccid ?? d.chipNaGeral ?? ''),

          mobileLineId: String(d.mobileLineId ?? ''),
          selectedClient,

          clienteInfo: selectedClient
            ? `GERAL: ${selectedClient} • Linha atual: ${d.linhaAtualNaGeral ?? '-'} • Usuário: ${d.usuario ?? '-'} • Chip: ${d.chipNaGeral ?? '-'}`
            : ''
        };

        if (selectedClient) {
          this.loadLinesForClient(selectedClient, 'edit');
        }

        this.cdr.detectChanges();
      },
      error: async () => {
        this.editOpen = false;
        await this.showToast('Erro ao abrir detalhes do registro.');
      }
    });
  }

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

  onEditClientChange() {
    const c = (this.editModel?.selectedClient ?? '').trim();

    this.editModel.mobileLineId = '';
    this.editModel.linhaAntiga = '';
    this.editModel.iccid = '';
    this.editModel.clienteInfo = c ? `Cliente selecionado: ${c}` : '';

    this.loadLinesForClient(c, 'edit');
  }

  onEditLineChange() {
    if (!this.editModel) return;
    this.applySelectedLineToModel(this.editModel, this.editModel.mobileLineId, this.lineOptionsEdit);
  }

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

    const mobileLineId = String(this.editModel.mobileLineId ?? '').trim();
    if (!mobileLineId) {
      this.showToast('Selecione Cliente e Linha Antiga (GERAL).');
      return;
    }

    this.editSaving = true;

    const payload: any = {
      item: this.toIntOrNull(this.editModel.item),
      mobileLineId,
      linhaAntiga: (this.editModel.linhaAntiga ?? '') || null,
      linhaNova: (this.editModel.linhaNova ?? '') || null,
      iccid: (this.editModel.iccid ?? '') || null,
      dataDaMureg: this.dateInputToIso(this.editModel.dataDaMureg)
    };

    if (payload.item == null) delete payload.item;

    this.http.put(`${this.apiBase}/${this.editModel.id}`, payload).subscribe({
      next: async () => {
        this.editSaving = false;
        await this.showToast('Registro atualizado com sucesso!');
        const currentGroup = this.expandedGroup;
        this.closeEdit();
        this.loadForGroups();

        if (currentGroup) {
          setTimeout(() => {
            this.expandedGroup = currentGroup;
            this.toggleGroup(currentGroup);
          }, 400);
        }
      },
      error: async (err) => {
        this.editSaving = false;
        const msg = this.extractApiMessage(err) ?? 'Erro ao salvar edição.';
        await this.showToast(msg);
      }
    });
  }

  // =======================================================================
  // DETAIL MODAL
  // =======================================================================
  onView(row: MuregRow) {
    this.detailOpen = true;
    this.detailLoading = true;
    this.detailData = null;

    this.http.get<MuregDetailDto>(`${this.apiBase}/${row.id}`).subscribe({
      next: (data) => {
        this.detailData = data;
        this.detailLoading = false;
      },
      error: async () => {
        this.detailLoading = false;
        await this.showToast('Erro ao carregar detalhes da Mureg.');
      }
    });
  }

  closeDetail() {
    this.detailOpen = false;
    this.detailLoading = false;
    this.detailData = null;
  }

  // =======================================================================
  // DELETE MODAL
  // =======================================================================
  onDelete(row: MuregRow) {
    this.deleteTarget = row;
    this.deleteOpen = true;
    this.deleteSaving = false;
  }

  closeDelete() {
    this.deleteOpen = false;
    this.deleteTarget = null;
    this.deleteSaving = false;
  }

  async confirmDelete() {
    if (!this.deleteTarget?.id) return;
    if (!(await confirmDeletionWithTyping('esta Mureg'))) return;

    this.deleteSaving = true;
    const targetId = this.deleteTarget.id;
    const currentGroup = this.expandedGroup;

    this.http.delete(`${this.apiBase}/${targetId}`).subscribe({
      next: async () => {
        this.deleteSaving = false;
        await this.showToast('Mureg excluída com sucesso!');
        this.closeDelete();
        this.loadForGroups();

        if (currentGroup) {
          setTimeout(() => {
            this.expandedGroup = currentGroup;
            this.toggleGroup(currentGroup);
          }, 400);
        }
      },
      error: async (err) => {
        this.deleteSaving = false;
        const msg = this.extractApiMessage(err) ?? 'Erro ao excluir Mureg.';
        await this.showToast(msg);
      }
    });
  }

  // =======================================================================
  // Helpers
  // =======================================================================
  private toIntOrZero(val: any): number {
    const n = parseInt(String(val ?? '').trim(), 10);
    return Number.isFinite(n) ? n : 0;
  }

  private toIntOrNull(val: any): number | null {
    const s = String(val ?? '').trim();
    if (!s) return null;
    const n = parseInt(s, 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();
  }

  private extractApiMessage(err: any): string | null {
    try {
      const m1 = err?.error?.message;
      if (m1) return String(m1);
      const m2 = err?.error?.title;
      if (m2) return String(m2);
      return null;
    } catch {
      return null;
    }
  }

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

    if (key === 'dataDaMureg') {
      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);
    }
  }
}
