// frontend/src/components/SimpleTable.tsx
import React, { useEffect, useState } from 'react';
import {
  useReactTable,
  getCoreRowModel,
  getFilteredRowModel,
  getSortedRowModel,
  getPaginationRowModel,
  flexRender,
  type CellContext
} from '@tanstack/react-table';
import { Tooltip } from 'react-tooltip';
import toast from 'react-hot-toast';
import type { Equipo, Sector, Usuario, UsuarioEquipoDetalle } from '../types/interfaces';
import styles from './SimpleTable.module.css';

import ModalAnadirEquipo from './ModalAnadirEquipo';
import ModalEditarSector from './ModalEditarSector';
import ModalCambiarClave from './ModalCambiarClave';
import ModalDetallesEquipo from './ModalDetallesEquipo';
import ModalAnadirDisco from './ModalAnadirDisco';
import ModalAnadirRam from './ModalAnadirRam';
import ModalAnadirUsuario from './ModalAnadirUsuario';

const SimpleTable = () => {
  const [data, setData] = useState<Equipo[]>([]);
  const [filteredData, setFilteredData] = useState<Equipo[]>([]);
  const [globalFilter, setGlobalFilter] = useState('');
  const [selectedSector, setSelectedSector] = useState('Todos');
  const [modalData, setModalData] = useState<Equipo | null>(null);
  const [sectores, setSectores] = useState<Sector[]>([]);
  const [modalPasswordData, setModalPasswordData] = useState<Usuario | null>(null);
  const [showScrollButton, setShowScrollButton] = useState(false);
  const [selectedEquipo, setSelectedEquipo] = useState<Equipo | null>(null);
  const [historial, setHistorial] = useState<any[]>([]);
  const [isOnline, setIsOnline] = useState(false);
  const [isAddModalOpen, setIsAddModalOpen] = useState(false);
  const [addingComponent, setAddingComponent] = useState<'disco' | 'ram' | 'usuario' | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const BASE_URL = 'http://localhost:5198/api';

  useEffect(() => {
    const scrollBarWidth = window.innerWidth - document.documentElement.clientWidth;
    if (selectedEquipo || modalData || modalPasswordData) {
      document.body.classList.add('scroll-lock');
      document.body.style.paddingRight = `${scrollBarWidth}px`;
    } else {
      document.body.classList.remove('scroll-lock');
      document.body.style.paddingRight = '0';
    }
    return () => {
      document.body.classList.remove('scroll-lock');
      document.body.style.paddingRight = '0';
    };
  }, [selectedEquipo, modalData, modalPasswordData]);

  useEffect(() => {
    if (!selectedEquipo) return;
    let isMounted = true;
    const checkPing = async () => {
      if (!selectedEquipo.ip) return;
      try {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), 5000);
        const response = await fetch(`${BASE_URL}/equipos/ping`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ ip: selectedEquipo.ip }),
          signal: controller.signal
        });
        clearTimeout(timeoutId);
        if (!response.ok) throw new Error('Error en la respuesta');
        const data = await response.json();
        if (isMounted) setIsOnline(data.isAlive);
      } catch (error) {
        if (isMounted) setIsOnline(false);
        console.error('Error checking ping:', error);
      }
    };
    checkPing();
    const interval = setInterval(checkPing, 10000);
    return () => {
      isMounted = false;
      clearInterval(interval);
      setIsOnline(false);
    };
  }, [selectedEquipo]);

  const handleCloseModal = () => {
    setSelectedEquipo(null);
    setIsOnline(false);
  };

  useEffect(() => {
    if (selectedEquipo) {
      fetch(`${BASE_URL}/equipos/${selectedEquipo.hostname}/historial`)
        .then(response => response.json())
        .then(data => setHistorial(data.historial))
        .catch(error => console.error('Error fetching history:', error));
    }
  }, [selectedEquipo]);

  useEffect(() => {
    const handleScroll = () => setShowScrollButton(window.scrollY > 200);
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  useEffect(() => {
    setIsLoading(true);
    Promise.all([
      fetch(`${BASE_URL}/equipos`).then(res => res.json()),
      fetch(`${BASE_URL}/sectores`).then(res => res.json())
    ]).then(([equiposData, sectoresData]) => {
      setData(equiposData);
      setFilteredData(equiposData);
      const sectoresOrdenados = [...sectoresData].sort((a, b) =>
        a.nombre.localeCompare(b.nombre, 'es', { sensitivity: 'base' })
      );
      setSectores(sectoresOrdenados);
    }).catch(error => {
      toast.error("No se pudieron cargar los datos iniciales.");
      console.error("Error al cargar datos:", error);
    }).finally(() => {
      setIsLoading(false);
    });
  }, []);

  const handleSectorChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const value = e.target.value;
    setSelectedSector(value);
    if (value === 'Todos') setFilteredData(data);
    else if (value === 'Asignar') setFilteredData(data.filter(i => !i.sector));
    else setFilteredData(data.filter(i => i.sector?.nombre === value));
  };

  const handleSave = async () => {
    if (!modalData || !modalData.sector) return;
    const toastId = toast.loading('Guardando...');
    try {
      const response = await fetch(`${BASE_URL}/equipos/${modalData.id}/sector/${modalData.sector.id}`, { method: 'PATCH' });
      if (!response.ok) throw new Error('Error al asociar el sector');
      const updatedData = data.map(e => e.id === modalData.id ? { ...e, sector: modalData.sector } : e);
      setData(updatedData);
      setFilteredData(updatedData);
      toast.success('Sector actualizado.', { id: toastId });
      setModalData(null);
    } catch (error) {
      toast.error('No se pudo actualizar.', { id: toastId });
      console.error(error);
    }
  };

  const handleSavePassword = async (password: string) => {
    if (!modalPasswordData) return;
    const toastId = toast.loading('Actualizando...');
    try {
      const response = await fetch(`${BASE_URL}/usuarios/${modalPasswordData.id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ password }),
      });
      if (!response.ok) {
        const err = await response.json();
        throw new Error(err.error || 'Error al actualizar');
      }
      const updatedUser = await response.json();
      const updatedData = data.map(equipo => ({
        ...equipo,
        usuarios: equipo.usuarios?.map(user => user.id === updatedUser.id ? { ...user, password } : user)
      }));
      setData(updatedData);
      setFilteredData(updatedData);
      toast.success(`Contraseña actualizada.`, { id: toastId });
      setModalPasswordData(null);
    } catch (error) {
      if (error instanceof Error) toast.error(error.message, { id: toastId });
    }
  };

  const handleRemoveUser = async (hostname: string, username: string) => {
    if (!window.confirm(`¿Quitar a ${username} de este equipo?`)) return;
    const toastId = toast.loading(`Quitando a ${username}...`);
    try {
      const response = await fetch(`${BASE_URL}/equipos/${hostname}/usuarios/${username}`, { method: 'DELETE' });
      const result = await response.json();
      if (!response.ok) throw new Error(result.error || 'Error al desasociar');
      const updateFunc = (prev: Equipo[]) => prev.map(e => e.hostname === hostname ? { ...e, usuarios: e.usuarios.filter(u => u.username !== username) } : e);
      setData(updateFunc);
      setFilteredData(updateFunc);
      toast.success(`${username} quitado.`, { id: toastId });
    } catch (error) {
      if (error instanceof Error) toast.error(error.message, { id: toastId });
    }
  };

  const handleDelete = async (id: number) => {
    if (!window.confirm('¿Eliminar este equipo y sus relaciones?')) return false;
    const toastId = toast.loading('Eliminando equipo...');
    try {
      const response = await fetch(`${BASE_URL}/equipos/${id}`, { method: 'DELETE' });
      if (response.status === 204) {
        setData(prev => prev.filter(e => e.id !== id));
        setFilteredData(prev => prev.filter(e => e.id !== id));
        toast.success('Equipo eliminado.', { id: toastId });
        return true;
      }
      const errorText = await response.text();
      throw new Error(errorText || 'Error desconocido');
    } catch (error) {
      if (error instanceof Error) toast.error(`Error: ${error.message}`, { id: toastId });
      return false;
    }
  };

  const handleRemoveAssociation = async (
    type: 'disco' | 'ram' | 'usuario',
    associationId: number | { equipoId: number, usuarioId: number }
  ) => {

    let url = '';
    let successMessage = '';

    if (type === 'disco' && typeof associationId === 'number') {
      url = `${BASE_URL}/equipos/asociacion/disco/${associationId}`;
      successMessage = 'Disco desasociado del equipo.';
    } else if (type === 'ram' && typeof associationId === 'number') {
      url = `${BASE_URL}/equipos/asociacion/ram/${associationId}`;
      successMessage = 'Módulo de RAM desasociado.';
    } else if (type === 'usuario' && typeof associationId === 'object') {
      url = `${BASE_URL}/equipos/asociacion/usuario/${associationId.equipoId}/${associationId.usuarioId}`;
      successMessage = 'Usuario desasociado del equipo.';
    } else {
      return; // No hacer nada si los parámetros son incorrectos
    }

    if (!window.confirm('¿Estás seguro de que quieres eliminar esta asociación manual?')) return;

    const toastId = toast.loading('Eliminando asociación...');
    try {
      const response = await fetch(url, { method: 'DELETE' });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.message || `Error al eliminar la asociación.`);
      }

      // Actualizar el estado local para reflejar el cambio inmediatamente
      const updateState = (prevEquipos: Equipo[]) => prevEquipos.map(equipo => {
        if (equipo.id !== selectedEquipo?.id) return equipo;

        let updatedEquipo = { ...equipo };
        if (type === 'disco' && typeof associationId === 'number') {
          updatedEquipo.discos = equipo.discos.filter(d => d.equipoDiscoId !== associationId);
        } else if (type === 'ram' && typeof associationId === 'number') {
          updatedEquipo.memoriasRam = equipo.memoriasRam.filter(m => m.equipoMemoriaRamId !== associationId);
        } else if (type === 'usuario' && typeof associationId === 'object') {
          updatedEquipo.usuarios = equipo.usuarios.filter(u => u.id !== associationId.usuarioId);
        }
        return updatedEquipo;
      });

      setData(updateState);
      setFilteredData(updateState);
      setSelectedEquipo(prev => prev ? updateState([prev])[0] : null); // Actualiza también el modal

      toast.success(successMessage, { id: toastId });
    } catch (error) {
      if (error instanceof Error) {
        toast.error(error.message, { id: toastId });
      }
    }
  };

  const handleCreateEquipo = async (nuevoEquipo: Omit<Equipo, 'id' | 'created_at' | 'updated_at'>) => {
    const toastId = toast.loading('Creando nuevo equipo...');
    try {
      const response = await fetch(`${BASE_URL}/equipos/manual`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(nuevoEquipo),
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.message || 'Error al crear el equipo.');
      }

      const equipoCreado = await response.json();

      // Actualizamos el estado local para ver el nuevo equipo inmediatamente
      setData(prev => [...prev, equipoCreado]);
      setFilteredData(prev => [...prev, equipoCreado]);

      toast.success(`Equipo '${equipoCreado.hostname}' creado.`, { id: toastId });
      setIsAddModalOpen(false); // Cerramos el modal
    } catch (error) {
      if (error instanceof Error) {
        toast.error(error.message, { id: toastId });
      }
    }
  };

  const handleEditEquipo = async (id: number, equipoEditado: Omit<Equipo, 'id' | 'created_at' | 'updated_at'>) => {
    const toastId = toast.loading('Guardando cambios...');
    try {
      const response = await fetch(`${BASE_URL}/equipos/manual/${id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(equipoEditado),
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.message || 'Error al actualizar el equipo.');
      }

      // Actualizar el estado local para reflejar los cambios
      const updateState = (prevEquipos: Equipo[]) => prevEquipos.map(equipo => {
        if (equipo.id === id) {
          return { ...equipo, ...equipoEditado };
        }
        return equipo;
      });

      setData(updateState);
      setFilteredData(updateState);
      setSelectedEquipo(prev => prev ? updateState([prev])[0] : null);

      toast.success('Equipo actualizado.', { id: toastId });
      return true; // Indica que el guardado fue exitoso
    } catch (error) {
      if (error instanceof Error) {
        toast.error(error.message, { id: toastId });
      }
      return false; // Indica que el guardado falló
    }
  };

  const handleAddComponent = async (type: 'disco' | 'ram' | 'usuario', data: any) => {
    if (!selectedEquipo) return;

    const toastId = toast.loading(`Añadiendo ${type}...`);
    try {
      const response = await fetch(`${BASE_URL}/equipos/manual/${selectedEquipo.id}/${type}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.message || `Error al añadir ${type}.`);
      }

      // Refrescar los datos del equipo para ver el cambio
      const refreshedEquipo = await (await fetch(`${BASE_URL}/equipos/${selectedEquipo.hostname}`)).json();

      const updateState = (prev: Equipo[]) => prev.map(e => e.id === selectedEquipo.id ? refreshedEquipo : e);
      setData(updateState);
      setFilteredData(updateState);
      setSelectedEquipo(refreshedEquipo);

      toast.success(`${type.charAt(0).toUpperCase() + type.slice(1)} añadido.`, { id: toastId });
      setAddingComponent(null); // Cerrar modal
    } catch (error) {
      if (error instanceof Error) toast.error(error.message, { id: toastId });
    }
  };

  const columns = [
    { header: "ID", accessorKey: "id", enableHiding: true },
    {
      header: "Nombre", accessorKey: "hostname",
      cell: ({ row }: CellContext<Equipo, any>) => (<button onClick={() => setSelectedEquipo(row.original)} className={styles.hostnameButton}>{row.original.hostname}</button>)
    },
    { header: "IP", accessorKey: "ip" },
    { header: "MAC", accessorKey: "mac", enableHiding: true },
    { header: "Motherboard", accessorKey: "motherboard" },
    { header: "CPU", accessorKey: "cpu" },
    { header: "RAM", accessorKey: "ram_installed" },
    { header: "Discos", accessorFn: (row: Equipo) => row.discos?.map(d => `${d.mediatype} ${d.size}GB`).join(" | ") || "Sin discos" },
    { header: "OS", accessorKey: "os" },
    { header: "Arquitectura", accessorKey: "architecture" },
    {
      header: "Usuarios y Claves",
      cell: ({ row }: CellContext<Equipo, any>) => {
        const usuarios = row.original.usuarios || [];
        return (
          <div className={styles.userList}>
            {usuarios.map((u: UsuarioEquipoDetalle) => (
              <div key={u.id} className={styles.userItem}>
                <span className={styles.userInfo}>
                  U: {u.username} - C: {u.password || 'N/A'}
                </span>

                <div className={styles.userActions}>
                  <button
                    onClick={() => setModalPasswordData(u)}
                    className={styles.tableButton}
                    data-tooltip-id={`edit-${u.id}`}
                  >
                    ✏️
                    <Tooltip id={`edit-${u.id}`} className={styles.tooltip} place="top">Cambiar Clave</Tooltip>
                  </button>

                  <button
                    onClick={() => handleRemoveUser(row.original.hostname, u.username)}
                    className={styles.deleteUserButton}
                    data-tooltip-id={`remove-${u.id}`}
                  >
                    🗑️
                    <Tooltip id={`remove-${u.id}`} className={styles.tooltip} place="top">Eliminar Usuario</Tooltip>
                  </button>
                </div>
              </div>
            ))}
          </div>
        );
      }
    },
    {
      header: "Sector", id: 'sector', accessorFn: (row: Equipo) => row.sector?.nombre || 'Asignar',
      cell: ({ row }: CellContext<Equipo, any>) => {
        const sector = row.original.sector;
        return (
          <div className={styles.sectorContainer}>
            <span className={`${styles.sectorName} ${sector ? styles.sectorNameAssigned : styles.sectorNameUnassigned}`}>{sector?.nombre || 'Asignar'}</span>
            <button onClick={() => setModalData(row.original)} className={styles.tableButton} data-tooltip-id={`editSector-${row.id}`}>✏️<Tooltip id={`editSector-${row.id}`} className={styles.tooltip} place="top">Cambiar Sector</Tooltip></button>
          </div>
        );
      }
    }
  ];

  const table = useReactTable({
    data: filteredData,
    columns,
    getCoreRowModel: getCoreRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    initialState: {
      sorting: [
        { id: 'sector', desc: false },
        { id: 'hostname', desc: false }
      ],
      columnVisibility: { id: false, mac: false },
      pagination: {
        pageSize: 15, // Mostrar 15 filas por página por defecto
      },
    },
    state: {
      globalFilter,
    },
    onGlobalFilterChange: setGlobalFilter,
  });

  if (isLoading) {
    return (
      <div style={{ padding: '2rem', textAlign: 'center' }}>
        <h2>Cargando Equipos...</h2>
      </div>
    );
  }

  const PaginacionControles = (
    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '1rem 0' }}>
      <div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
        <button onClick={() => table.setPageIndex(0)} disabled={!table.getCanPreviousPage()} className={styles.tableButton}>
          {'<<'}
        </button>
        <button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()} className={styles.tableButton}>
          {'<'}
        </button>
        <button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()} className={styles.tableButton}>
          {'>'}
        </button>
        <button onClick={() => table.setPageIndex(table.getPageCount() - 1)} disabled={!table.getCanNextPage()} className={styles.tableButton}>
          {'>>'}
        </button>
      </div>
      <span>
        Página{' '}
        <strong>
          {table.getState().pagination.pageIndex + 1} de {table.getPageCount()}
        </strong>
      </span>
      <div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
        <span>| Ir a pág:</span>
        <input
          type="number"
          defaultValue={table.getState().pagination.pageIndex + 1}
          onChange={e => {
            const page = e.target.value ? Number(e.target.value) - 1 : 0;
            table.setPageIndex(page);
          }}
          style={{ width: '60px' }}
          className={styles.searchInput}
        />
        <select
          value={table.getState().pagination.pageSize}
          onChange={e => {
            table.setPageSize(Number(e.target.value));
          }}
          className={styles.sectorSelect}
        >
          {[10, 15, 25, 50, 100].map(pageSize => (
            <option key={pageSize} value={pageSize}>
              Mostrar {pageSize}
            </option>
          ))}
        </select>
      </div>
    </div>
  );

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <h2>Equipos ({table.getFilteredRowModel().rows.length})</h2>
        <button
          className={`${styles.btn} ${styles.btnPrimary}`}
          onClick={() => setIsAddModalOpen(true)}
        >
          + Añadir Equipo
        </button>
      </div>
      <div className={styles.controlsContainer}>
        <input type="text" placeholder="Buscar en todos los campos..." value={globalFilter} onChange={(e) => setGlobalFilter(e.target.value)} className={styles.searchInput} style={{ width: '300px' }} />
        <b>Sector:</b>
        <select value={selectedSector} onChange={handleSectorChange} className={styles.sectorSelect}>
          <option value="Todos">-Todos-</option>
          <option value="Asignar">-Asignar-</option>
          {sectores.map(s => (<option key={s.id} value={s.nombre}>{s.nombre}</option>))}
        </select>
      </div>

      {/* --- 2. Renderizar los controles ANTES de la tabla --- */}
      {PaginacionControles}

      <div style={{ overflowX: 'auto', maxHeight: '70vh', border: '1px solid #dee2e6', borderRadius: '8px' }}>
        <table className={styles.table}>
          <thead>
            {table.getHeaderGroups().map(hg => (
              <tr key={hg.id}>
                {hg.headers.map(h => (
                  <th key={h.id} className={styles.th}>
                    {flexRender(h.column.columnDef.header, h.getContext())}
                    {h.column.getIsSorted() && (<span className={styles.sortIndicator}>{h.column.getIsSorted() === 'asc' ? '⇑' : '⇓'}</span>)}
                  </th>
                ))}
              </tr>
            ))}
          </thead>
          <tbody>
            {table.getRowModel().rows.map(row => (
              <tr key={row.id} className={styles.tr}>
                {row.getVisibleCells().map(cell => (
                  <td key={cell.id} className={styles.td}>
                    {flexRender(cell.column.columnDef.cell, cell.getContext())}
                  </td>
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {/* --- 3. Renderizar los controles DESPUÉS de la tabla --- */}
      {PaginacionControles}

      {showScrollButton && (<button onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} className={styles.scrollToTop} title="Volver arriba">↑</button>)}

      {modalData && (
        <ModalEditarSector
          modalData={modalData}
          setModalData={setModalData}
          sectores={sectores}
          onClose={() => setModalData(null)}
          onSave={handleSave}
        />
      )}

      {modalPasswordData && (
        <ModalCambiarClave
          usuario={modalPasswordData}
          onClose={() => setModalPasswordData(null)}
          onSave={handleSavePassword}
        />
      )}

      {selectedEquipo && (
        <ModalDetallesEquipo
          equipo={selectedEquipo}
          isOnline={isOnline}
          historial={historial}
          onClose={handleCloseModal}
          onDelete={handleDelete}
          onRemoveAssociation={handleRemoveAssociation}
          onEdit={handleEditEquipo}
          sectores={sectores}
          onAddComponent={type => setAddingComponent(type)}
        />
      )}

      {isAddModalOpen && (
        <ModalAnadirEquipo
          sectores={sectores}
          onClose={() => setIsAddModalOpen(false)}
          onSave={handleCreateEquipo}
        />
      )}

      {addingComponent === 'disco' && <ModalAnadirDisco onClose={() => setAddingComponent(null)} onSave={(data) => handleAddComponent('disco', data)} />}
      {addingComponent === 'ram' && <ModalAnadirRam onClose={() => setAddingComponent(null)} onSave={(data) => handleAddComponent('ram', data)} />}
      {addingComponent === 'usuario' && <ModalAnadirUsuario onClose={() => setAddingComponent(null)} onSave={(data) => handleAddComponent('usuario', data)} />}
    </div>
  );
};

export default SimpleTable;