import * as SQLite from "expo-sqlite";

const dbPromise = SQLite.openDatabaseAsync("toptran.db");

export type UserDB = {
  id: string;
  email: string;
  name: string;
  token: string;
  createdAt: string;
};

export type RideDB = {
  id: string;
  user_id: string;
  company: string;
  km: number;
  cost_per_km: number;
  total: number;
  ride_date: string;
  synced: 0 | 1;
  createdAt: string;
};

export type CompanyDB = {
  id: string;
  name: string;
  cost_per_km: number;
  notes: string;
  createdAt: string;
};

export const initDB = async () => {
  try {
    const db = await dbPromise;
    await db.execAsync(
      `CREATE TABLE IF NOT EXISTS users (
        id TEXT PRIMARY KEY,
        email TEXT UNIQUE NOT NULL,
        name TEXT NOT NULL,
        token TEXT NOT NULL,
        createdAt TEXT DEFAULT CURRENT_TIMESTAMP
      );`,
    );
    await db.execAsync(
      `CREATE TABLE IF NOT EXISTS rides (
        id TEXT PRIMARY KEY,
        user_id TEXT NOT NULL,
        company TEXT NOT NULL,
        km REAL NOT NULL,
        cost_per_km REAL NOT NULL,
        total REAL NOT NULL,
        ride_date TEXT NOT NULL,
        synced INTEGER DEFAULT 0,
        createdAt TEXT DEFAULT CURRENT_TIMESTAMP,
        FOREIGN KEY (user_id) REFERENCES users(id)
      );`,
    );
    await db.execAsync(
      `CREATE TABLE IF NOT EXISTS settings (
        key TEXT PRIMARY KEY,
        value TEXT NOT NULL
      );`,
    );
    await db.execAsync(
      `CREATE TABLE IF NOT EXISTS companies (
        id TEXT PRIMARY KEY,
        name TEXT NOT NULL,
        cost_per_km REAL NOT NULL,
        notes TEXT DEFAULT '',
        createdAt TEXT DEFAULT CURRENT_TIMESTAMP
      );`,
    );
  } catch (error) {
    console.error("Failed to initialize database:", error);
    throw error;
  }
};

// SETTINGS (key-value store)
export const getSetting = async (key: string): Promise<string | null> => {
  try {
    const db = await dbPromise;
    const row = await db.getFirstAsync<{ value: string }>(
      `SELECT value FROM settings WHERE key = ?`,
      [key],
    );
    return row?.value ?? null;
  } catch (error) {
    console.error("Error reading setting:", error);
    throw error;
  }
};

export const setSetting = async (key: string, value: string): Promise<void> => {
  try {
    const db = await dbPromise;
    await db.runAsync(
      `INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)`,
      [key, value],
    );
  } catch (error) {
    console.error("Error writing setting:", error);
    throw error;
  }
};

export const deleteSetting = async (key: string): Promise<void> => {
  try {
    const db = await dbPromise;
    await db.runAsync(`DELETE FROM settings WHERE key = ?`, [key]);
  } catch (error) {
    console.error("Error deleting setting:", error);
    throw error;
  }
};

// USERS
export const salvarUsuario = async (
  usuario: Omit<UserDB, "createdAt">,
): Promise<string> => {
  try {
    const db = await dbPromise;
    const existing = await db.getFirstAsync<{ id: string }>(
      `SELECT id FROM users WHERE email = ?`,
      [usuario.email],
    );

    if (existing) {
      if (existing.id !== usuario.id) {
        // Migra rides do ID local antigo para o ID real do backend
        await db.runAsync(
          `UPDATE rides SET user_id = ? WHERE user_id = ?`,
          [usuario.id, existing.id],
        );
        await db.runAsync(
          `UPDATE users SET id = ?, name = ?, token = ? WHERE email = ?`,
          [usuario.id, usuario.name, usuario.token, usuario.email],
        );
      } else {
        await db.runAsync(
          `UPDATE users SET name = ?, token = ? WHERE email = ?`,
          [usuario.name, usuario.token, usuario.email],
        );
      }
      return usuario.id;
    }

    await db.runAsync(
      `INSERT INTO users (id, email, name, token) VALUES (?, ?, ?, ?)`,
      [usuario.id, usuario.email, usuario.name, usuario.token],
    );
    return usuario.id;
  } catch (error) {
    console.error("Error saving user:", error);
    throw error;
  }
};

export const obterUsuario = async (
  usuarioId: string,
): Promise<UserDB | null> => {
  try {
    const db = await dbPromise;
    const result = await db.getFirstAsync<UserDB>(
      `SELECT * FROM users WHERE id = ?`,
      [usuarioId],
    );
    return result || null;
  } catch (error) {
    console.error("Error fetching user:", error);
    throw error;
  }
};

// RIDES
export const salvarCorrida = async (corrida: Omit<RideDB, "createdAt">) => {
  try {
    const db = await dbPromise;
    const result = await db.runAsync(
      `INSERT INTO rides (id, user_id, company, km, cost_per_km, total, ride_date, synced)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
      [
        corrida.id,
        corrida.user_id,
        corrida.company,
        corrida.km,
        corrida.cost_per_km,
        corrida.total,
        corrida.ride_date,
        corrida.synced,
      ],
    );
    return result;
  } catch (error) {
    console.error("Error saving ride:", error);
    throw error;
  }
};

export const obterCorridas = async (
  usuarioId: string,
): Promise<RideDB[]> => {
  try {
    const db = await dbPromise;
    const result = await db.getAllAsync<RideDB>(
      `SELECT * FROM rides WHERE user_id = ? ORDER BY createdAt DESC`,
      [usuarioId],
    );
    return result || [];
  } catch (error) {
    console.error("Error fetching rides:", error);
    throw error;
  }
};

export const obterCorridasNaoSincronizadas = async (
  usuarioId: string,
): Promise<RideDB[]> => {
  try {
    const db = await dbPromise;
    const result = await db.getAllAsync<RideDB>(
      `SELECT * FROM rides WHERE user_id = ? AND synced = 0`,
      [usuarioId],
    );
    return result || [];
  } catch (error) {
    console.error("Error fetching unsynced rides:", error);
    throw error;
  }
};

export const marcarCorridaComoSincronizada = async (corridaId: string) => {
  try {
    const db = await dbPromise;
    await db.runAsync(`UPDATE rides SET synced = 1 WHERE id = ?`, [corridaId]);
  } catch (error) {
    console.error("Error marking ride as synced:", error);
    throw error;
  }
};

export const deletarCorrida = async (corridaId: string) => {
  try {
    const db = await dbPromise;
    await db.runAsync(`DELETE FROM rides WHERE id = ?`, [corridaId]);
  } catch (error) {
    console.error("Error deleting ride:", error);
    throw error;
  }
};

export const limparBancoDados = async () => {
  try {
    const db = await dbPromise;
    await db.execAsync(`DELETE FROM rides; DELETE FROM users;`);
    console.log("Database cleared");
  } catch (error) {
    console.error("Error clearing database:", error);
    throw error;
  }
};

// COMPANIES
export const obterEmpresas = async (): Promise<CompanyDB[]> => {
  try {
    const db = await dbPromise;
    return (
      (await db.getAllAsync<CompanyDB>(
        `SELECT * FROM companies ORDER BY name ASC`,
      )) ?? []
    );
  } catch (error) {
    console.error("Error fetching companies:", error);
    throw error;
  }
};

export const salvarEmpresa = async (
  empresa: Omit<CompanyDB, "createdAt">,
): Promise<void> => {
  try {
    const db = await dbPromise;
    await db.runAsync(
      `INSERT INTO companies (id, name, cost_per_km, notes) VALUES (?, ?, ?, ?)`,
      [empresa.id, empresa.name, empresa.cost_per_km, empresa.notes],
    );
  } catch (error) {
    console.error("Error saving company:", error);
    throw error;
  }
};

export const upsertEmpresaLocal = async (
  empresa: Omit<CompanyDB, "createdAt">,
): Promise<void> => {
  try {
    const db = await dbPromise;
    await db.runAsync(
      `INSERT OR REPLACE INTO companies (id, name, cost_per_km, notes) VALUES (?, ?, ?, ?)`,
      [empresa.id, empresa.name, empresa.cost_per_km, empresa.notes],
    );
  } catch (error) {
    console.error("Error upserting company:", error);
    throw error;
  }
};

export const upsertCorridaLocal = async (
  corrida: Omit<RideDB, "createdAt">,
): Promise<void> => {
  try {
    const db = await dbPromise;
    await db.runAsync(
      `INSERT OR REPLACE INTO rides (id, user_id, company, km, cost_per_km, total, ride_date, synced)
       VALUES (?, ?, ?, ?, ?, ?, ?, 1)`,
      [corrida.id, corrida.user_id, corrida.company, corrida.km, corrida.cost_per_km, corrida.total, corrida.ride_date],
    );
  } catch (error) {
    console.error("Error upserting ride:", error);
    throw error;
  }
};

export const atualizarEmpresa = async (
  empresa: Omit<CompanyDB, "createdAt">,
): Promise<void> => {
  try {
    const db = await dbPromise;
    await db.runAsync(
      `UPDATE companies SET name = ?, cost_per_km = ?, notes = ? WHERE id = ?`,
      [empresa.name, empresa.cost_per_km, empresa.notes, empresa.id],
    );
  } catch (error) {
    console.error("Error updating company:", error);
    throw error;
  }
};

export const deletarEmpresa = async (id: string): Promise<void> => {
  try {
    const db = await dbPromise;
    await db.runAsync(`DELETE FROM companies WHERE id = ?`, [id]);
  } catch (error) {
    console.error("Error deleting company:", error);
    throw error;
  }
};
