import Dexie, { Table } from 'dexie';

export interface DbOrdenTrabajo {
  localId: string;
  serverId?: number;
  numeroOt?: string;
  clienteTarjeta: string;
  vehiculo: any;
  fechaEntrada: Date;
  fechaSalida?: Date;
  km: number;
  nivelGasolina: number;
  requerimientoCliente?: string;
  observaciones?: string;
  estado: string;
  cosasTrae: number[];
  danos: any[];
  fotos: any[];
  firma?: any;
  cotizacion?: any;
  syncStatus: 'pending' | 'synced' | 'conflict';
  lastModified: number;
  version: number;
}

export interface DbCliente {
  tarjeta: string;
  nombre: string;
  nit?: string;
  direccion?: string;
  telefono?: string;
  celular?: string;
  email?: string;
  syncStatus: 'pending' | 'synced';
  lastModified: number;
}

export interface DbVehiculo {
  localId: string;
  serverId?: number;
  placa: string;
  marca?: string;
  modelo?: string;
  anio?: number;
  motor?: string;
  cilindraje?: string;
  color?: string;
  tipoVehiculoId: number;
  clienteId?: string;
  clienteIds?: string[];
  syncStatus: 'pending' | 'synced';
  lastModified: number;
}

export interface DbProducto {
  plu: string;
  desclarga: string;
  desccorta?: string;
  precio: number;
  iva: number;
  pagaiva: boolean;
  tipo: string;
  es_servicio: boolean;
  usainventario?: boolean;
  estaller?: boolean;
  origen?: 'local' | 'erp';
  cachedAt: number;
}

export interface DbCatalogo {
  id: number;
  tipo: 'tipo_vehiculo' | 'cosa_trae' | 'tipo_dano';
  nombre: string;
  descripcion?: string;
  extra?: any;
  cachedAt: number;
}

export interface DbSyncEvent {
  id?: number;
  eventId: string;
  eventType: string;
  entityType: string;
  localId: string;
  payload: any;
  timestamp: number;
  status: 'pending' | 'sent' | 'failed';
  retries: number;
  error?: string;
}

export interface DbSettings {
  key: string;
  value: any;
}

class TallerDatabase extends Dexie {
  ordenesTrabajo!: Table<DbOrdenTrabajo>;
  clientes!: Table<DbCliente>;
  vehiculos!: Table<DbVehiculo>;
  productos!: Table<DbProducto>;
  catalogos!: Table<DbCatalogo>;
  syncEvents!: Table<DbSyncEvent>;
  settings!: Table<DbSettings>;
  otFotos!: Table<any>;
  otDanos!: Table<any>;

  constructor() {
    super('TallerPWA');

    this.version(32).stores({
      ordenesTrabajo: 'localId, serverId, numeroOt, clienteTarjeta, estado, syncStatus, lastModified',
      clientes: 'tarjeta, nombre, syncStatus',
      vehiculos: 'localId, serverId, placa, clienteId, *clienteIds, syncStatus',
      productos: 'plu, desclarga, tipo, cachedAt',
      catalogos: '[tipo+id], tipo, cachedAt',
      syncEvents: '++id, eventId, eventType, status, timestamp',
      settings: 'key',
      otFotos: 'id, otLocalId, tipo, synced',
      otDanos: 'id, otLocalId, tipoDanoId, synced',
    });
  }
}

export const db = new TallerDatabase();

if (typeof window !== 'undefined') {
  db.open().catch(async (error: any) => {
    const message = String(error?.message || '');
    const isVersionError = error?.name === 'VersionError' || message.includes('VersionError');

    if (isVersionError) {
      console.warn('[db] Version mismatch detected. Resetting local IndexedDB schema...');
      db.close();
      await Dexie.delete('TallerPWA');
      window.location.reload();
      return;
    }

    throw error;
  });
}

export async function addSyncEvent(
  eventType: string,
  entityType: string,
  localId: string,
  payload: any
): Promise<void> {
  const eventId = crypto.randomUUID();

  await db.syncEvents.add({
    eventId,
    eventType,
    entityType,
    localId,
    payload,
    timestamp: Date.now(),
    status: 'pending',
    retries: 0,
  });
}

export async function getPendingSyncEvents(): Promise<DbSyncEvent[]> {
  return db.syncEvents
    .where('status')
    .equals('pending')
    .sortBy('timestamp');
}

export async function markEventSent(eventId: string): Promise<void> {
  await db.syncEvents
    .where('eventId')
    .equals(eventId)
    .modify({ status: 'sent' });
}

export async function markEventFailed(eventId: string, error: string): Promise<void> {
  await db.syncEvents
    .where('eventId')
    .equals(eventId)
    .modify((event) => {
      event.status = 'failed';
      event.retries = (event.retries || 0) + 1;
      event.error = error;
    });
}

export async function getLastSyncTimestamp(): Promise<number> {
  const setting = await db.settings.get('lastSyncTimestamp');
  return setting?.value || 0;
}

export async function setLastSyncTimestamp(timestamp: number): Promise<void> {
  await db.settings.put({ key: 'lastSyncTimestamp', value: timestamp });
}
