import AsyncStorage from "@react-native-async-storage/async-storage"
import { Platform } from "react-native"
import * as SQLite from 'expo-sqlite'

// Verificar se estamos em um ambiente que suporta SQLite
let db: any
let usingSQLite = false

// Função para inicializar SQLite com expo-sqlite
const initializeSQLite = async (): Promise<boolean> => {
  try {
    if (Platform.OS === "web") {
      return false;
    }

    if (typeof SQLite.openDatabaseAsync !== "function") {
      return false;
    }

    db = await SQLite.openDatabaseAsync("truckdelivery.db");
    
    if (!db) {
      return false;
    }

    // Testar se o banco está funcionando
    await db.execAsync(`
      PRAGMA journal_mode = WAL;
      SELECT name FROM sqlite_master WHERE type='table' LIMIT 1;
    `);

    return true;
  } catch (error) {
    return false;
  }
};

// Função para executar queries de forma robusta
const executeQuery = async (query: string, params: any[] = []): Promise<any> => {
  try {
    if (!usingSQLite || !db) {
      throw new Error("SQLite não está disponível");
    }

    const isSelect = query.trim().toUpperCase().startsWith('SELECT');

    if (isSelect) {
      const result = await db.getAllAsync(query, params);
      return {
        rows: {
          _array: result,
          length: result.length
        }
      };
    } else {
      const result = await db.runAsync(query, params);
      return {
        rows: {
          _array: [],
          length: 0
        },
        insertId: result.lastInsertRowId,
        rowsAffected: result.changes
      };
    }
  } catch (error) {
    throw error;
  }
};

// Inicializar SQLite e aguardar conclusão
let sqliteInitialized = false;

const initializeSQLiteAsync = async (): Promise<void> => {
  try {
    const success = await initializeSQLite();
    
    usingSQLite = success;
    sqliteInitialized = true;
  } catch (error) {
    usingSQLite = false;
    sqliteInitialized = true;
  }
};

// Inicializar SQLite imediatamente
initializeSQLiteAsync();

// Prefixos para as chaves do AsyncStorage (apenas para configurações)
const USERS_KEY = "@TruckDelivery:users:"
const DELIVERIES_KEY = "@TruckDelivery:deliveries:"
const ROUTES_KEY = "@TruckDelivery:routes:"
const SETTINGS_KEY = "@TruckDelivery:settings:"

// Função para limpar dados antigos do AsyncStorage
export const clearOldAsyncStorageData = async (): Promise<void> => {
  try {
    const keys = await AsyncStorage.getAllKeys();
    const oldKeys = keys.filter(key => 
      key.startsWith('@TruckDelivery:deliveries:') ||
      key.startsWith('@TruckDelivery:customers:') ||
      key.startsWith('@TruckDelivery:invoices:')
    );
    
    if (oldKeys.length > 0) {
      await AsyncStorage.multiRemove(oldKeys);
    }
  } catch (error) {
    // Ignorar erro
  }
};

// Função para inicializar o banco de dados
export const setupDatabase = async (): Promise<void> => {
  // Aguardar inicialização do SQLite
  while (!sqliteInitialized) {
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  // Primeiro, limpar dados antigos do AsyncStorage
  await clearOldAsyncStorageData();
  
  if (usingSQLite) {
    try {
      // Criar todas as tabelas usando execAsync
      await db.execAsync(`
        PRAGMA journal_mode = WAL;
        
        -- Tabela de usuários
        CREATE TABLE IF NOT EXISTS users (
          id TEXT PRIMARY KEY,
          name TEXT,
          email TEXT,
          role TEXT,
          last_login INTEGER
        );

        -- Tabela de entregas
        CREATE TABLE IF NOT EXISTS deliveries (
          id TEXT PRIMARY KEY,
          outId TEXT,
          customerId TEXT,
          customerName TEXT,
          street TEXT,
          streetNumber TEXT,
          neighborhood TEXT,
          city TEXT,
          state TEXT,
          zipCode TEXT,
          customerPhone TEXT,
          lat REAL,
          lng REAL,
          latFrom REAL,
          lngFrom REAL,
          deliverySeq INTEGER,
          routing INTEGER,
          sellerId TEXT,
          storeId TEXT,
          status TEXT,
          outDate TEXT,
          notes TEXT,
          signature TEXT,
          photos TEXT,
          completedTime INTEGER,
          completedBy TEXT,
          version INTEGER DEFAULT 1,
          lastModified INTEGER DEFAULT (strftime('%s', 'now')),
          syncTimestamp INTEGER,
          syncStatus TEXT DEFAULT 'pending'
        );

        -- Tabela de clientes
        CREATE TABLE IF NOT EXISTS customers (
          id TEXT PRIMARY KEY,
          name TEXT,
          street TEXT,
          streetNumber TEXT,
          neighborhood TEXT,
          city TEXT,
          state TEXT,
          zipCode TEXT,
          phone TEXT,
          lat REAL,
          lng REAL,
          created_at INTEGER DEFAULT (strftime('%s', 'now'))
        );

        -- Tabela de controle de sincronização
        CREATE TABLE IF NOT EXISTS sync_control (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          table_name TEXT UNIQUE,
          last_sync INTEGER,
          sync_status TEXT DEFAULT 'pending',
          created_at INTEGER DEFAULT (strftime('%s', 'now'))
        );

        -- Tabela de conflitos de sincronização
        CREATE TABLE IF NOT EXISTS sync_conflicts (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          table_name TEXT,
          record_id TEXT,
          local_data TEXT,
          server_data TEXT,
          conflict_type TEXT,
          resolved BOOLEAN DEFAULT FALSE,
          created_at INTEGER DEFAULT (strftime('%s', 'now'))
        );

        -- Tabela de log de sincronização
        CREATE TABLE IF NOT EXISTS sync_log (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          action TEXT,
          table_name TEXT,
          record_id TEXT,
          status TEXT,
          error_message TEXT,
          timestamp INTEGER DEFAULT (strftime('%s', 'now'))
        );

        -- Tabela de notas fiscais dos clientes
        CREATE TABLE IF NOT EXISTS customer_invoices (
          id TEXT PRIMARY KEY,
          invoiceId TEXT,
          transactionId INTEGER,
          customerId TEXT,
          customerName TEXT,
          invoiceValue REAL,
          status TEXT,
          items TEXT,
          created_at INTEGER DEFAULT (strftime('%s', 'now')),
          sync_status TEXT DEFAULT 'pending'
        );

        -- Tabela de imagens das entregas
        CREATE TABLE IF NOT EXISTS delivery_images (
          id TEXT PRIMARY KEY,
          deliveryId TEXT,
          transactionId INTEGER,
          imagePath TEXT,
          imageUrl TEXT,
          uploadStatus TEXT DEFAULT 'pending',
          uploadAttempts INTEGER DEFAULT 0,
          lastUploadAttempt INTEGER,
          created_at INTEGER DEFAULT (strftime('%s', 'now')),
          FOREIGN KEY (deliveryId) REFERENCES deliveries(id)
        );

        -- Tabela de fila de sincronização
        CREATE TABLE IF NOT EXISTS sync_queue (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          table_name TEXT NOT NULL,
          record_id TEXT NOT NULL,
          action TEXT NOT NULL,
          data TEXT,
          priority INTEGER DEFAULT 1,
          attempts INTEGER DEFAULT 0,
          max_attempts INTEGER DEFAULT 3,
          last_attempt INTEGER,
          created_at INTEGER DEFAULT (strftime('%s', 'now')),
          status TEXT DEFAULT 'pending'
        );

        -- Tabela de uploads de fotos
        CREATE TABLE IF NOT EXISTS photo_uploads (
          id TEXT PRIMARY KEY,
          deliveryId TEXT,
          transactionId INTEGER,
          localPath TEXT,
          serverUrl TEXT,
          uploadStatus TEXT DEFAULT 'pending',
          uploadProgress REAL DEFAULT 0,
          uploadAttempts INTEGER DEFAULT 0,
          lastUploadAttempt INTEGER,
          errorMessage TEXT,
          created_at INTEGER DEFAULT (strftime('%s', 'now')),
          FOREIGN KEY (deliveryId) REFERENCES deliveries(id)
        );

        -- Tabela de entregas individuais por nota fiscal
        CREATE TABLE IF NOT EXISTS delivery_invoices (
          id TEXT PRIMARY KEY,
          deliveryId TEXT,
          outId TEXT,
          transactionId INTEGER,
          deliveryDate TEXT,
          receiverDoc TEXT,
          receiverName TEXT,
          lat TEXT,
          lng TEXT,
          broken BOOLEAN DEFAULT FALSE,
          devolution BOOLEAN DEFAULT FALSE,
          reasonDevolution TEXT,
          deliveryImages TEXT,
          userId INTEGER,
          status TEXT DEFAULT 'pending',
          syncStatus TEXT DEFAULT 'pending',
          created_at INTEGER DEFAULT (strftime('%s', 'now')),
          lastModified INTEGER DEFAULT (strftime('%s', 'now')),
          FOREIGN KEY (deliveryId) REFERENCES deliveries(id)
        );

        -- Tabela de configurações
        CREATE TABLE IF NOT EXISTS settings (
          key TEXT PRIMARY KEY,
          value TEXT
        );

        -- Criar índices para melhor performance
        CREATE INDEX IF NOT EXISTS idx_deliveries_customer ON deliveries(customerId);
        CREATE INDEX IF NOT EXISTS idx_deliveries_status ON deliveries(status);
        CREATE INDEX IF NOT EXISTS idx_deliveries_routing ON deliveries(routing);
        CREATE INDEX IF NOT EXISTS idx_sync_queue_status ON sync_queue(status);
        CREATE INDEX IF NOT EXISTS idx_photo_uploads_status ON photo_uploads(uploadStatus);
        CREATE INDEX IF NOT EXISTS idx_delivery_invoices_deliveryId ON delivery_invoices(deliveryId);
        CREATE INDEX IF NOT EXISTS idx_delivery_invoices_syncStatus ON delivery_invoices(syncStatus);
      `);

    } catch (error) {
      throw error;
    }
  } else {
    // Configurar AsyncStorage com valores padrão
    await AsyncStorage.setItem(SETTINGS_KEY + "offline_mode", "true")
    await AsyncStorage.setItem(SETTINGS_KEY + "initial_data_loaded", "false")
    await AsyncStorage.setItem(SETTINGS_KEY + "last_sync_time", "0")
  }
}

// Função para obter configurações
export const getSetting = async (key: string): Promise<string | null> => {
  try {
    if (usingSQLite) {
      const result = await executeQuery(
        "SELECT value FROM settings WHERE key = ?",
        [key]
      )
      return result.rows && result.rows._array && result.rows._array.length > 0 
        ? result.rows._array[0].value 
        : null
    } else {
      return await AsyncStorage.getItem(SETTINGS_KEY + key)
    }
  } catch (error) {
    return null
  }
}

// Função para salvar configurações
export const saveSetting = async (key: string, value: string): Promise<void> => {
  try {
    if (usingSQLite) {
      await executeQuery(
        "INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)",
        [key, value]
      )
    } else {
      await AsyncStorage.setItem(SETTINGS_KEY + key, value)
    }
  } catch (error) {
  }
}

// Função para obter entregas do banco local (APENAS SQLite)
export const getDeliveriesFromLocal = async (): Promise<any[]> => {
  try {
    if (!usingSQLite) {
      throw new Error('SQLite not available - app requires SQLite to function');
    }

    const result = await executeQuery(`
      SELECT 
        id, outId, customerId, customerName, street, streetNumber, neighborhood,
        city, state, zipCode, customerPhone, lat, lng, latFrom, lngFrom,
        deliverySeq, routing, sellerId, storeId, status, outDate, notes,
        signature, photos, completedTime, completedBy, version, lastModified,
        syncTimestamp, syncStatus
      FROM deliveries 
      ORDER BY deliverySeq ASC, lastModified DESC
    `);
    
    const deliveries = result.rows._array.map(row => ({
      id: row.id,
      outId: row.outId,
      customerId: row.customerId,
      customerName: row.customerName,
      street: row.street,
      streetNumber: row.streetNumber,
      neighborhood: row.neighborhood,
      city: row.city,
      state: row.state,
      zipCode: row.zipCode,
      customerPhone: row.customerPhone,
      lat: row.lat,
      lng: row.lng,
      latFrom: row.latFrom,
      lngFrom: row.lngFrom,
      deliverySeq: row.deliverySeq,
      routing: row.routing,
      sellerId: row.sellerId,
      storeId: row.storeId,
      status: row.status,
      outDate: row.outDate,
      notes: row.notes,
      signature: row.signature,
      photos: row.photos ? JSON.parse(row.photos) : [],
      completedTime: row.completedTime,
      completedBy: row.completedBy,
      version: row.version,
      lastModified: row.lastModified,
      syncTimestamp: row.syncTimestamp,
      syncStatus: row.syncStatus,
      coordinates: row.lat && row.lng ? {
        latitude: parseFloat(row.lat.toString().replace(',', '.')),
        longitude: parseFloat(row.lng.toString().replace(',', '.'))
      } : undefined
    }));
    
    return deliveries;
  } catch (error) {
    throw error;
  }
};

// Função para obter a próxima entrega do banco local
export const getNextDeliveryFromLocal = async (): Promise<any | null> => {
  try {
    if (!usingSQLite) {
      return null;
    }

    // Buscar a primeira entrega que não está entregue, ordenada por deliverySeq
    const result = await executeQuery(`
      SELECT 
        id, outId, customerId, customerName, street, streetNumber, neighborhood,
        city, state, zipCode, customerPhone, lat, lng, latFrom, lngFrom,
        deliverySeq, routing, sellerId, storeId, status, outDate, notes,
        signature, photos, completedTime, completedBy, version, lastModified,
        syncTimestamp, syncStatus
      FROM deliveries 
      WHERE deliverySeq > 0 AND status != 'delivered'
      ORDER BY deliverySeq ASC
      LIMIT 1
    `);
    
    if (result.rows.length === 0) {
      return null;
    }
    
    const row = result.rows._array[0];
    const nextDelivery = {
      id: row.id,
      outId: row.outId,
      customerId: row.customerId,
      customerName: row.customerName,
      street: row.street,
      streetNumber: row.streetNumber,
      neighborhood: row.neighborhood,
      city: row.city,
      state: row.state,
      zipCode: row.zipCode,
      customerPhone: row.customerPhone,
      lat: row.lat,
      lng: row.lng,
      latFrom: row.latFrom,
      lngFrom: row.lngFrom,
      deliverySeq: row.deliverySeq,
      routing: row.routing,
      sellerId: row.sellerId,
      storeId: row.storeId,
      status: row.status,
      outDate: row.outDate,
      notes: row.notes,
      signature: row.signature,
      photos: row.photos ? JSON.parse(row.photos) : [],
      completedTime: row.completedTime,
      completedBy: row.completedBy,
      version: row.version,
      lastModified: row.lastModified,
      syncTimestamp: row.syncTimestamp,
      syncStatus: row.syncStatus,
      coordinates: row.lat && row.lng ? {
        latitude: parseFloat(row.lat.toString().replace(',', '.')),
        longitude: parseFloat(row.lng.toString().replace(',', '.'))
      } : undefined
    };
    
    return nextDelivery;
  } catch (error) {
    return null;
  }
};

// Função para obter notas fiscais do banco local
export const getCustomerInvoicesFromLocal = async (customerId: string): Promise<any[]> => {
  try {
    if (usingSQLite) {
      const result = await executeQuery(`
        SELECT 
          id, invoiceId, transactionId, customerId, customerName, 
          invoiceValue, status, items, created_at, sync_status
        FROM customer_invoices 
        WHERE customerId = ?
        ORDER BY created_at DESC
      `, [customerId]);
      
      
      const invoices = result.rows._array.map(row => ({
        id: row.id,
        invoiceId: row.invoiceId,
        transactionId: row.transactionId,
        customerId: row.customerId,
        customerName: row.customerName,
        invoiceValue: row.invoiceValue,
        status: row.status,
        itens: row.items ? JSON.parse(row.items) : [],
        createdAt: row.created_at,
        syncStatus: row.sync_status
      }));
      
      return invoices;
    } else {
      return [];
    }
  } catch (error) {
    return [];
  }
};

export const getDatabaseStats = async (): Promise<any> => {
  try {
    if (usingSQLite) {
      const deliveriesResult = await executeQuery("SELECT COUNT(*) as count FROM deliveries")
      const photosResult = await executeQuery("SELECT COUNT(*) as count FROM photo_uploads")
      const signaturesResult = await executeQuery("SELECT COUNT(*) as count FROM deliveries WHERE signature IS NOT NULL")
      const statusResult = await executeQuery("SELECT COUNT(*) as count FROM sync_queue WHERE status = 'pending'")
      const syncQueueResult = await executeQuery("SELECT COUNT(*) as count FROM sync_queue")

      return {
        deliveries: deliveriesResult.rows.item(0).count,
        photos: photosResult.rows.item(0).count,
        signatures: signaturesResult.rows.item(0).count,
        status: statusResult.rows.item(0).count,
        syncQueue: syncQueueResult.rows.item(0).count,
        totalSize: 0 // Placeholder
      }
    } else {
      return {
        deliveries: 0,
        photos: 0,
        signatures: 0,
        status: 0,
        syncQueue: 0,
        totalSize: 0
      }
    }
  } catch (error) {
    return {
      deliveries: 0,
      photos: 0,
      signatures: 0,
      status: 0,
      syncQueue: 0,
      totalSize: 0
    }
  }
}

// Informações sobre o tipo de armazenamento
export const storageInfo = {
  type: usingSQLite ? 'SQLite' : 'AsyncStorage',
  usingSQLite: usingSQLite
}

// Função para salvar entrega individual por nota fiscal
export const saveDeliveryInvoice = async (deliveryInvoice: {
  id: string;
  deliveryId: string;
  outId: string;
  transactionId: number;
  deliveryDate: string;
  receiverDoc: string;
  receiverName: string;
  lat: string;
  lng: string;
  broken: boolean;
  devolution: boolean;
  reasonDevolution: string;
  deliveryImages: string;
  userId: number;
}): Promise<void> => {
  try {
    if (!usingSQLite) {
      throw new Error('SQLite not available');
    }
    
    const now = Date.now();
    
    await executeQuery(`
      INSERT OR REPLACE INTO delivery_invoices (
        id, deliveryId, outId, transactionId, deliveryDate, receiverDoc, receiverName,
        lat, lng, broken, devolution, reasonDevolution, deliveryImages, userId,
        status, syncStatus, created_at, lastModified
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `, [
      deliveryInvoice.id,
      deliveryInvoice.deliveryId,
      deliveryInvoice.outId,
      deliveryInvoice.transactionId,
      deliveryInvoice.deliveryDate,
      deliveryInvoice.receiverDoc,
      deliveryInvoice.receiverName,
      deliveryInvoice.lat,
      deliveryInvoice.lng,
      deliveryInvoice.broken ? 1 : 0,
      deliveryInvoice.devolution ? 1 : 0,
      deliveryInvoice.reasonDevolution,
      deliveryInvoice.deliveryImages,
      deliveryInvoice.userId,
      'pending',
      'pending',
      now,
      now
    ]);
    
  } catch (error) {
    throw error;
  }
};

// Função para obter entregas individuais pendentes de sincronização
export const getPendingDeliveryInvoices = async (): Promise<any[]> => {
  try {
    if (!usingSQLite) {
      return [];
    }
    
    const result = await executeQuery(`
      SELECT 
        id, deliveryId, outId, transactionId, deliveryDate, receiverDoc, receiverName,
        lat, lng, broken, devolution, reasonDevolution, deliveryImages, userId,
        status, syncStatus, created_at, lastModified
      FROM delivery_invoices 
      WHERE syncStatus = 'pending'
      ORDER BY created_at ASC
    `);
    
    const deliveryInvoices = result.rows._array.map(row => ({
      id: row.id,
      deliveryId: row.deliveryId,
      outId: row.outId,
      transactionId: row.transactionId,
      deliveryDate: row.deliveryDate,
      receiverDoc: row.receiverDoc,
      receiverName: row.receiverName,
      lat: row.lat,
      lng: row.lng,
      broken: row.broken === 1,
      devolution: row.devolution === 1,
      reasonDevolution: row.reasonDevolution,
      deliveryImages: row.deliveryImages ? JSON.parse(row.deliveryImages) : [],
      userId: row.userId,
      status: row.status,
      syncStatus: row.syncStatus,
      createdAt: row.created_at,
      lastModified: row.lastModified
    }));
    
    return deliveryInvoices;
  } catch (error) {
    return [];
  }
};

// Função para marcar entrega individual como sincronizada
export const markDeliveryInvoiceAsSynced = async (deliveryInvoiceId: string): Promise<void> => {
  try {
    if (!usingSQLite) {
      return;
    }
    
    const now = Date.now();
    
    await executeQuery(`
      UPDATE delivery_invoices 
      SET syncStatus = 'synced', lastModified = ?
      WHERE id = ?
    `, [now, deliveryInvoiceId]);
    
  } catch (error) {
    throw error;
  }
};

// Função para salvar upload de foto
export const savePhotoUpload = async (photoUpload: any): Promise<void> => {
  try {
    if (!usingSQLite) {
      throw new Error('SQLite not available');
    }
    const query = `
      INSERT OR REPLACE INTO photo_uploads (
        id, deliveryId, transactionId, localPath, serverUrl, 
        uploadStatus, uploadProgress, uploadAttempts, lastUploadAttempt, errorMessage
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `;
    
    const params = [
      photoUpload.id,
      photoUpload.deliveryId,
      photoUpload.transactionId,
      photoUpload.localPath,
      photoUpload.serverUrl || null,
      photoUpload.uploadStatus,
      photoUpload.uploadProgress,
      photoUpload.uploadAttempts,
      photoUpload.lastUploadAttempt || null,
      photoUpload.errorMessage || null
    ];
    
    await executeQuery(query, params);
  } catch (error) {
    throw error;
  }
};

// Função para obter uploads de fotos pendentes
export const getPendingPhotoUploads = async (): Promise<any[]> => {
  try {
    if (usingSQLite) {
      const result = await executeQuery(`
        SELECT * FROM photo_uploads 
        WHERE uploadStatus = 'pending' OR uploadStatus = 'failed'
        ORDER BY created_at ASC
      `);
      
      const uploads = result.rows._array.map(row => ({
        id: row.id,
        deliveryId: row.deliveryId,
        transactionId: row.transactionId,
        localPath: row.localPath,
        serverUrl: row.serverUrl,
        uploadStatus: row.uploadStatus,
        uploadProgress: row.uploadProgress,
        uploadAttempts: row.uploadAttempts,
        lastUploadAttempt: row.lastUploadAttempt,
        errorMessage: row.errorMessage
      }));
      
      return uploads;
    } else {
      return [];
    }
  } catch (error) {
    return [];
  }
};

// Função para salvar imagem de entrega
export const saveDeliveryImage = async (imageData: any): Promise<void> => {
  try {
    
    if (usingSQLite) {
      await executeQuery(`
        INSERT OR REPLACE INTO delivery_images (
          id, deliveryId, transactionId, imagePath, imageUrl, uploadStatus
        ) VALUES (?, ?, ?, ?, ?, ?)
      `, [
        imageData.id,
        imageData.deliveryId,
        imageData.transactionId,
        imageData.imagePath,
        imageData.imageUrl,
        imageData.uploadStatus
      ]);
      
    } else {
      throw new Error('SQLite not available');
    }
  } catch (error) {
    throw error;
  }
};

// Exportar variáveis e funções necessárias
export { usingSQLite, executeQuery }
export default { setupDatabase, getSetting, saveSetting, getDeliveriesFromLocal, getCustomerInvoicesFromLocal, getDatabaseStats, clearOldAsyncStorageData, savePhotoUpload, getPendingPhotoUploads, saveDeliveryImage }