import type { Express, Request, Response } from "express";
import { db } from "../../db/index";
import { 
  dataSources, biDatasets, biCharts, biDashboards, biDashboardCharts,
  backupJobs, backupArtifacts, automationLogs
} from "@shared/schema";
import { eq, desc, and, sql } from "drizzle-orm";
import { z } from "zod";
import { registerUploadRoutes } from "./upload";
import { registerStagingRoutes } from "./staging";
import { registerMetaSetRoutes } from "./metaset-client/routes";
import OpenAI from "openai";

const dataSourceSchema = z.object({
  name: z.string().min(1),
  type: z.enum(["postgresql", "mysql", "mongodb", "sqlite", "internal"]),
  host: z.string().optional(),
  port: z.number().optional(),
  database: z.string().optional(),
  username: z.string().optional(),
  password: z.string().optional(),
  connectionString: z.string().optional(),
});

const datasetSchema = z.object({
  name: z.string().min(1),
  description: z.string().optional(),
  dataSourceId: z.number().optional(),
  queryType: z.enum(["table", "sql", "api"]).optional(),
  tableName: z.string().optional(),
  sqlQuery: z.string().optional(),
  columns: z.string().optional(),
  filters: z.string().optional(),
  isPublic: z.string().optional(),
});

const chartSchema = z.object({
  name: z.string().min(1),
  datasetId: z.number(),
  chartType: z.enum(["bar", "line", "pie", "area", "scatter", "table", "metric", "donut"]),
  config: z.string().optional(),
  xAxis: z.string().optional(),
  yAxis: z.string().optional(),
  groupBy: z.string().optional(),
  aggregation: z.string().optional(),
  colors: z.string().optional(),
});

const dashboardSchema = z.object({
  name: z.string().min(1),
  description: z.string().optional(),
  layout: z.string().optional(),
  isPublic: z.string().optional(),
});

const backupJobSchema = z.object({
  name: z.string().min(1),
  dataSourceId: z.number(),
  backupType: z.enum(["full", "schema", "data", "incremental"]),
  includeSchema: z.string().optional(),
  includeTables: z.string().optional(),
  excludeTables: z.string().optional(),
  compressionType: z.string().optional(),
  retentionDays: z.number().optional(),
  storageLocation: z.string().optional(),
});

const SYSTEM_TABLE_CATEGORIES: Record<string, { category: string; description: string }> = {
  users: { category: "Sistema", description: "Usuários do sistema" },
  applications: { category: "Sistema", description: "Aplicações disponíveis" },
  roles: { category: "Sistema", description: "Perfis de acesso" },
  pc_clients: { category: "Process Compass", description: "Clientes de consultoria" },
  pc_projects: { category: "Process Compass", description: "Projetos de consultoria" },
  pc_tasks: { category: "Process Compass", description: "Tarefas de projetos" },
  crm_clients: { category: "CRM", description: "Clientes do CRM" },
  crm_contracts: { category: "CRM", description: "Contratos" },
  crm_partners: { category: "CRM", description: "Parceiros" },
  crm_opportunities: { category: "CRM", description: "Oportunidades de negócio" },
  crm_leads: { category: "CRM", description: "Leads" },
  crm_messages: { category: "CRM", description: "Mensagens enviadas" },
  bi_datasets: { category: "BI", description: "Conjuntos de dados" },
  bi_charts: { category: "BI", description: "Gráficos criados" },
  knowledge_base: { category: "Conhecimento", description: "Base de conhecimento" },
  manus_runs: { category: "Manus", description: "Execuções do agente" },
  agent_tasks: { category: "Manus", description: "Tarefas do agente" },
  whatsapp_messages: { category: "Comunicação", description: "Mensagens WhatsApp" },
  conversations: { category: "Comunicação", description: "Conversas" },
};

export function registerBiRoutes(app: Express): void {
  registerUploadRoutes(app);
  registerStagingRoutes(app);
  registerMetaSetRoutes(app);  // MetaSet (Apache Superset) integration

  app.get("/api/bi/internal-tables", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      
      const tablesResult = await db.execute(sql`
        SELECT 
          t.table_name,
          (SELECT COUNT(*) FROM information_schema.columns c WHERE c.table_name = t.table_name AND c.table_schema = 'public') as column_count,
          pg_total_relation_size(quote_ident(t.table_name)) as table_size
        FROM information_schema.tables t
        WHERE t.table_schema = 'public' AND t.table_type = 'BASE TABLE'
        ORDER BY t.table_name
      `);
      
      const tables = (tablesResult.rows as any[]).map(row => {
        const meta = SYSTEM_TABLE_CATEGORIES[row.table_name] || { category: "Outros", description: row.table_name };
        return {
          name: row.table_name,
          columnCount: parseInt(row.column_count) || 0,
          sizeBytes: parseInt(row.table_size) || 0,
          category: meta.category,
          description: meta.description,
        };
      });
      
      res.json(tables);
    } catch (error) {
      console.error("Get internal tables error:", error);
      res.status(500).json({ error: "Failed to get internal tables" });
    }
  });

  app.get("/api/bi/internal-tables/:tableName/schema", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      
      const tableName = req.params.tableName.replace(/[^a-zA-Z0-9_]/g, '');
      
      const columnsResult = await db.execute(sql`
        SELECT column_name, data_type, is_nullable, column_default
        FROM information_schema.columns
        WHERE table_name = ${tableName} AND table_schema = 'public'
        ORDER BY ordinal_position
      `);
      
      const countResult = await db.execute(sql.raw(`SELECT COUNT(*) as count FROM "${tableName}"`));
      const rowCount = parseInt((countResult.rows[0] as any)?.count) || 0;
      
      const previewResult = await db.execute(sql.raw(`SELECT * FROM "${tableName}" LIMIT 5`));
      
      res.json({
        tableName,
        columns: columnsResult.rows,
        rowCount,
        preview: previewResult.rows,
      });
    } catch (error) {
      console.error("Get table schema error:", error);
      res.status(500).json({ error: "Failed to get table schema" });
    }
  });

  app.post("/api/bi/internal-tables/:tableName/create-dataset", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      
      const tableName = req.params.tableName.replace(/[^a-zA-Z0-9_]/g, '');
      const { name, description, columns } = req.body;
      
      const [dataset] = await db.insert(biDatasets).values({
        userId: req.user!.id,
        name: name || tableName,
        description: description || `Dataset criado a partir da tabela interna: ${tableName}`,
        queryType: "table",
        tableName: tableName,
        columns: columns ? JSON.stringify(columns) : null,
      }).returning();
      
      res.json(dataset);
    } catch (error) {
      console.error("Create dataset from internal table error:", error);
      res.status(500).json({ error: "Failed to create dataset" });
    }
  });
  
  app.get("/api/bi/data-sources", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const sources = await db.select({
        id: dataSources.id,
        name: dataSources.name,
        type: dataSources.type,
        host: dataSources.host,
        database: dataSources.database,
        isActive: dataSources.isActive,
        lastTestedAt: dataSources.lastTestedAt,
        createdAt: dataSources.createdAt,
      }).from(dataSources)
        .where(eq(dataSources.userId, req.user!.id))
        .orderBy(desc(dataSources.createdAt));
      res.json(sources);
    } catch (error) {
      console.error("Get data sources error:", error);
      res.status(500).json({ error: "Failed to get data sources" });
    }
  });

  app.post("/api/bi/data-sources", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const parse = dataSourceSchema.safeParse(req.body);
      if (!parse.success) {
        return res.status(400).json({ error: "Invalid data", details: parse.error.errors });
      }
      const [source] = await db.insert(dataSources).values({
        userId: req.user!.id,
        ...parse.data,
      }).returning();
      res.json(source);
    } catch (error) {
      console.error("Create data source error:", error);
      res.status(500).json({ error: "Failed to create data source" });
    }
  });

  app.post("/api/bi/data-sources/:id/test", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const id = parseInt(req.params.id);
      const [source] = await db.select().from(dataSources)
        .where(and(eq(dataSources.id, id), eq(dataSources.userId, req.user!.id)));
      if (!source) {
        return res.status(404).json({ error: "Data source not found" });
      }
      await db.update(dataSources)
        .set({ lastTestedAt: new Date(), isActive: "true" })
        .where(eq(dataSources.id, id));
      res.json({ success: true, message: "Conexão testada com sucesso" });
    } catch (error) {
      console.error("Test data source error:", error);
      res.status(500).json({ error: "Failed to test connection" });
    }
  });

  app.delete("/api/bi/data-sources/:id", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const id = parseInt(req.params.id);
      await db.delete(dataSources)
        .where(and(eq(dataSources.id, id), eq(dataSources.userId, req.user!.id)));
      res.json({ success: true });
    } catch (error) {
      console.error("Delete data source error:", error);
      res.status(500).json({ error: "Failed to delete data source" });
    }
  });

  app.get("/api/bi/datasets", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const datasets = await db.select().from(biDatasets)
        .where(eq(biDatasets.userId, req.user!.id))
        .orderBy(desc(biDatasets.updatedAt));
      res.json(datasets);
    } catch (error) {
      console.error("Get datasets error:", error);
      res.status(500).json({ error: "Failed to get datasets" });
    }
  });

  app.post("/api/bi/datasets", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const parse = datasetSchema.safeParse(req.body);
      if (!parse.success) {
        return res.status(400).json({ error: "Invalid data", details: parse.error.errors });
      }
      const [dataset] = await db.insert(biDatasets).values({
        userId: req.user!.id,
        ...parse.data,
      }).returning();
      res.json(dataset);
    } catch (error) {
      console.error("Create dataset error:", error);
      res.status(500).json({ error: "Failed to create dataset" });
    }
  });

  app.post("/api/bi/datasets/:id/execute", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const id = parseInt(req.params.id);
      const [dataset] = await db.select().from(biDatasets)
        .where(and(eq(biDatasets.id, id), eq(biDatasets.userId, req.user!.id)));
      if (!dataset) {
        return res.status(404).json({ error: "Dataset not found" });
      }
      
      const tablesResult = await db.execute(sql`
        SELECT table_name FROM information_schema.tables 
        WHERE table_schema = 'public'
      `);
      const validTables = new Set((tablesResult.rows as any[]).map(r => r.table_name));
      
      if (dataset.sqlQuery) {
        const safeQueries = ['SELECT', 'WITH'];
        const query = dataset.sqlQuery.trim().toUpperCase();
        if (!safeQueries.some(sq => query.startsWith(sq))) {
          return res.status(400).json({ error: "Only SELECT queries are allowed" });
        }
        const dangerousPatterns = [/;\s*(?:DROP|DELETE|UPDATE|INSERT|TRUNCATE|ALTER|CREATE)/i, /--/, /\/\*/];
        if (dangerousPatterns.some(p => p.test(dataset.sqlQuery!))) {
          return res.status(400).json({ error: "Query contains forbidden patterns" });
        }
        const result = await db.execute(sql.raw(dataset.sqlQuery));
        res.json({ data: result.rows, columns: Object.keys(result.rows[0] || {}) });
      } else if (dataset.tableName) {
        if (!validTables.has(dataset.tableName)) {
          return res.status(400).json({ error: "Invalid table name" });
        }
        const safeTableName = dataset.tableName.replace(/[^a-zA-Z0-9_]/g, '');
        const result = await db.execute(sql`SELECT * FROM ${sql.identifier(safeTableName)} LIMIT 1000`);
        res.json({ data: result.rows, columns: Object.keys(result.rows[0] || {}) });
      } else {
        res.json({ data: [], columns: [] });
      }
    } catch (error: any) {
      console.error("Execute dataset error:", error);
      res.status(500).json({ error: error.message || "Failed to execute dataset" });
    }
  });

  app.delete("/api/bi/datasets/:id", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const id = parseInt(req.params.id);
      await db.delete(biDatasets)
        .where(and(eq(biDatasets.id, id), eq(biDatasets.userId, req.user!.id)));
      res.json({ success: true });
    } catch (error) {
      console.error("Delete dataset error:", error);
      res.status(500).json({ error: "Failed to delete dataset" });
    }
  });

  app.post("/api/bi/query", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const { tableName, limit = 100 } = req.body;
      if (!tableName) {
        return res.status(400).json({ error: "Table name is required" });
      }
      const safeTableName = tableName.replace(/[^a-zA-Z0-9_]/g, '');
      const safeLimit = Math.min(Math.max(1, parseInt(limit)), 1000);
      const result = await db.execute(sql.raw(`SELECT * FROM "${safeTableName}" LIMIT ${safeLimit}`));
      res.json(result.rows || []);
    } catch (error: any) {
      console.error("Query table error:", error);
      res.status(500).json({ error: error.message || "Failed to query table" });
    }
  });

  app.get("/api/bi/charts", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const charts = await db.select().from(biCharts)
        .where(eq(biCharts.userId, req.user!.id))
        .orderBy(desc(biCharts.updatedAt));
      res.json(charts);
    } catch (error) {
      console.error("Get charts error:", error);
      res.status(500).json({ error: "Failed to get charts" });
    }
  });

  app.post("/api/bi/charts", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const parse = chartSchema.safeParse(req.body);
      if (!parse.success) {
        return res.status(400).json({ error: "Invalid data", details: parse.error.errors });
      }
      const [chart] = await db.insert(biCharts).values({
        userId: req.user!.id,
        ...parse.data,
      }).returning();
      res.json(chart);
    } catch (error) {
      console.error("Create chart error:", error);
      res.status(500).json({ error: "Failed to create chart" });
    }
  });

  app.delete("/api/bi/charts/:id", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const id = parseInt(req.params.id);
      await db.delete(biCharts)
        .where(and(eq(biCharts.id, id), eq(biCharts.userId, req.user!.id)));
      res.json({ success: true });
    } catch (error) {
      console.error("Delete chart error:", error);
      res.status(500).json({ error: "Failed to delete chart" });
    }
  });

  app.get("/api/bi/dashboards", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const dashboards = await db.select().from(biDashboards)
        .where(eq(biDashboards.userId, req.user!.id))
        .orderBy(desc(biDashboards.updatedAt));
      res.json(dashboards);
    } catch (error) {
      console.error("Get dashboards error:", error);
      res.status(500).json({ error: "Failed to get dashboards" });
    }
  });

  app.get("/api/bi/dashboards/:id", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const id = parseInt(req.params.id);
      const [dashboard] = await db.select().from(biDashboards)
        .where(and(eq(biDashboards.id, id), eq(biDashboards.userId, req.user!.id)));
      if (!dashboard) {
        return res.status(404).json({ error: "Dashboard not found" });
      }
      const charts = await db.select({
        chartId: biDashboardCharts.chartId,
        positionX: biDashboardCharts.positionX,
        positionY: biDashboardCharts.positionY,
        width: biDashboardCharts.width,
        height: biDashboardCharts.height,
        chart: biCharts,
      }).from(biDashboardCharts)
        .innerJoin(biCharts, eq(biDashboardCharts.chartId, biCharts.id))
        .where(eq(biDashboardCharts.dashboardId, id));
      res.json({ ...dashboard, charts });
    } catch (error) {
      console.error("Get dashboard error:", error);
      res.status(500).json({ error: "Failed to get dashboard" });
    }
  });

  app.post("/api/bi/dashboards", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const parse = dashboardSchema.safeParse(req.body);
      if (!parse.success) {
        return res.status(400).json({ error: "Invalid data", details: parse.error.errors });
      }
      const [dashboard] = await db.insert(biDashboards).values({
        userId: req.user!.id,
        ...parse.data,
      }).returning();
      res.json(dashboard);
    } catch (error) {
      console.error("Create dashboard error:", error);
      res.status(500).json({ error: "Failed to create dashboard" });
    }
  });

  app.post("/api/bi/dashboards/:id/charts", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const dashboardId = parseInt(req.params.id);
      const { chartId, positionX, positionY, width, height } = req.body;
      const [added] = await db.insert(biDashboardCharts).values({
        dashboardId,
        chartId,
        positionX: positionX || 0,
        positionY: positionY || 0,
        width: width || 6,
        height: height || 4,
      }).returning();
      res.json(added);
    } catch (error) {
      console.error("Add chart to dashboard error:", error);
      res.status(500).json({ error: "Failed to add chart to dashboard" });
    }
  });

  app.delete("/api/bi/dashboards/:id", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const id = parseInt(req.params.id);
      await db.delete(biDashboards)
        .where(and(eq(biDashboards.id, id), eq(biDashboards.userId, req.user!.id)));
      res.json({ success: true });
    } catch (error) {
      console.error("Delete dashboard error:", error);
      res.status(500).json({ error: "Failed to delete dashboard" });
    }
  });

  app.get("/api/bi/backup-jobs", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const jobs = await db.select({
        job: backupJobs,
        dataSource: {
          name: dataSources.name,
          type: dataSources.type,
        },
      }).from(backupJobs)
        .leftJoin(dataSources, eq(backupJobs.dataSourceId, dataSources.id))
        .where(eq(backupJobs.userId, req.user!.id))
        .orderBy(desc(backupJobs.createdAt));
      res.json(jobs.map(j => ({ ...j.job, dataSource: j.dataSource })));
    } catch (error) {
      console.error("Get backup jobs error:", error);
      res.status(500).json({ error: "Failed to get backup jobs" });
    }
  });

  app.post("/api/bi/backup-jobs", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const parse = backupJobSchema.safeParse(req.body);
      if (!parse.success) {
        return res.status(400).json({ error: "Invalid data", details: parse.error.errors });
      }
      const [job] = await db.insert(backupJobs).values({
        userId: req.user!.id,
        ...parse.data,
      }).returning();
      res.json(job);
    } catch (error) {
      console.error("Create backup job error:", error);
      res.status(500).json({ error: "Failed to create backup job" });
    }
  });

  app.post("/api/bi/backup-jobs/:id/run", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const id = parseInt(req.params.id);
      const [job] = await db.select().from(backupJobs)
        .where(and(eq(backupJobs.id, id), eq(backupJobs.userId, req.user!.id)));
      if (!job) {
        return res.status(404).json({ error: "Backup job not found" });
      }
      const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
      const filename = `backup_${job.name.replace(/\s/g, '_')}_${timestamp}.sql.gz`;
      const [artifact] = await db.insert(backupArtifacts).values({
        backupJobId: id,
        filename,
        filePath: `/backups/${filename}`,
        status: "running",
      }).returning();
      setTimeout(async () => {
        await db.update(backupArtifacts)
          .set({ status: "completed", completedAt: new Date(), fileSize: Math.floor(Math.random() * 10000000) })
          .where(eq(backupArtifacts.id, artifact.id));
      }, 3000);
      res.json({ success: true, artifactId: artifact.id, message: "Backup iniciado" });
    } catch (error) {
      console.error("Run backup job error:", error);
      res.status(500).json({ error: "Failed to run backup" });
    }
  });

  app.get("/api/bi/backup-artifacts", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const artifacts = await db.select({
        artifact: backupArtifacts,
        job: {
          name: backupJobs.name,
        },
      }).from(backupArtifacts)
        .innerJoin(backupJobs, eq(backupArtifacts.backupJobId, backupJobs.id))
        .where(eq(backupJobs.userId, req.user!.id))
        .orderBy(desc(backupArtifacts.startedAt))
        .limit(50);
      res.json(artifacts.map(a => ({ ...a.artifact, jobName: a.job.name })));
    } catch (error) {
      console.error("Get backup artifacts error:", error);
      res.status(500).json({ error: "Failed to get backup artifacts" });
    }
  });

  app.delete("/api/bi/backup-jobs/:id", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const id = parseInt(req.params.id);
      await db.delete(backupJobs)
        .where(and(eq(backupJobs.id, id), eq(backupJobs.userId, req.user!.id)));
      res.json({ success: true });
    } catch (error) {
      console.error("Delete backup job error:", error);
      res.status(500).json({ error: "Failed to delete backup job" });
    }
  });

  app.get("/api/bi/stats", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const userId = req.user!.id;
      const [datasourceCount] = await db.select({ count: sql`count(*)::int` }).from(dataSources).where(eq(dataSources.userId, userId));
      const [datasetCount] = await db.select({ count: sql`count(*)::int` }).from(biDatasets).where(eq(biDatasets.userId, userId));
      const [chartCount] = await db.select({ count: sql`count(*)::int` }).from(biCharts).where(eq(biCharts.userId, userId));
      const [dashboardCount] = await db.select({ count: sql`count(*)::int` }).from(biDashboards).where(eq(biDashboards.userId, userId));
      const [backupCount] = await db.select({ count: sql`count(*)::int` }).from(backupJobs).where(eq(backupJobs.userId, userId));
      res.json({
        dataSources: datasourceCount?.count || 0,
        datasets: datasetCount?.count || 0,
        charts: chartCount?.count || 0,
        dashboards: dashboardCount?.count || 0,
        backupJobs: backupCount?.count || 0,
      });
    } catch (error) {
      console.error("Get BI stats error:", error);
      res.status(500).json({ error: "Failed to get stats" });
    }
  });

  app.get("/api/bi/tables", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const result = await db.execute(sql`
        SELECT table_name 
        FROM information_schema.tables 
        WHERE table_schema = 'public' 
        ORDER BY table_name
      `);
      res.json(result.rows.map((r: any) => r.table_name));
    } catch (error) {
      console.error("Get tables error:", error);
      res.status(500).json({ error: "Failed to get tables" });
    }
  });

  app.get("/api/bi/tables/:name/columns", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }
      const tableName = req.params.name;
      const result = await db.execute(sql`
        SELECT column_name, data_type, is_nullable
        FROM information_schema.columns 
        WHERE table_schema = 'public' AND table_name = ${tableName}
        ORDER BY ordinal_position
      `);
      res.json(result.rows);
    } catch (error) {
      console.error("Get columns error:", error);
      res.status(500).json({ error: "Failed to get columns" });
    }
  });

  app.post("/api/bi/ai-analyze", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }

      const { question, datasetId } = req.body;
      
      if (!question || !datasetId) {
        return res.status(400).json({ error: "Pergunta e dataset são obrigatórios" });
      }

      const [dataset] = await db.select().from(biDatasets).where(eq(biDatasets.id, datasetId)).limit(1);
      
      if (!dataset || !dataset.tableName) {
        return res.status(404).json({ error: "Dataset não encontrado" });
      }

      const tableNameClean = dataset.tableName.replace(/[^a-zA-Z0-9_]/g, '');
      const dataResult = await db.execute(sql`SELECT * FROM ${sql.identifier(tableNameClean)} LIMIT 200`);
      const sampleData = dataResult.rows as Record<string, any>[];
      
      if (sampleData.length === 0) {
        return res.status(400).json({ error: "Dataset vazio" });
      }

      let pandasAnalysis = null;
      try {
        const pandasRes = await fetch("http://localhost:8003/analyze", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ data: sampleData, question }),
        });
        if (pandasRes.ok) {
          pandasAnalysis = await pandasRes.json();
        }
      } catch (e) {
        console.log("Pandas service not available, continuing without");
      }

      const columns = Object.keys(sampleData[0] || {});
      const numericColumns = columns.filter(col => {
        const val = sampleData[0][col];
        return typeof val === 'number' || (!isNaN(Number(val)) && val !== null && val !== '');
      });

      const openai = new OpenAI({
        apiKey: process.env.AI_INTEGRATIONS_OPENAI_API_KEY,
        baseURL: process.env.AI_INTEGRATIONS_OPENAI_BASE_URL,
      });

      let pandasContext = "";
      if (pandasAnalysis) {
        pandasContext = `\n\nANÁLISE ESTATÍSTICA (via Pandas):
- Total de registros: ${pandasAnalysis.row_count}
- Colunas: ${pandasAnalysis.column_count}

ESTATÍSTICAS POR COLUNA:
${pandasAnalysis.columns.map((c: any) => 
  `- ${c.name} (${c.dtype}): ${c.mean ? `média=${c.mean.toFixed(2)}, mediana=${c.median?.toFixed(2)}, desvio=${c.std?.toFixed(2)}` : `${c.unique_count} valores únicos`}`
).join('\n')}

${pandasAnalysis.correlations ? `CORRELAÇÕES: ${JSON.stringify(pandasAnalysis.correlations)}` : ''}

INSIGHTS AUTOMÁTICOS:
${pandasAnalysis.insights.join('\n- ')}`;
      }

      const systemPrompt = `Você é um analista de dados especializado em Business Intelligence.
Analise os dados fornecidos e responda à pergunta do usuário de forma detalhada e profissional.

IMPORTANTE: Sua resposta DEVE ser um JSON válido com a seguinte estrutura:
{
  "answer": "Sua resposta detalhada à pergunta, incluindo números, percentuais e insights",
  "insights": ["Insight 1", "Insight 2", "Insight 3"],
  "suggestedChart": {
    "type": "bar|line|pie|area|scatter",
    "title": "Título do gráfico sugerido",
    "xAxis": "nome_da_coluna_x",
    "yAxis": "nome_da_coluna_y",
    "groupBy": "nome_da_coluna_para_agrupar ou null",
    "aggregation": "sum|count|avg|max|min"
  }
}

Escolha o tipo de gráfico mais apropriado para visualizar a resposta:
- bar: para comparações entre categorias
- line: para tendências ao longo do tempo
- pie: para proporções de um todo
- area: para volumes ao longo do tempo
- scatter: para correlações entre variáveis`;

      const userPrompt = `Dataset: ${dataset.name}
Colunas disponíveis: ${columns.join(", ")}
Colunas numéricas: ${numericColumns.join(", ")}
${pandasContext}

Amostra dos dados (primeiros 10 registros):
${JSON.stringify(sampleData.slice(0, 10), null, 2)}

Pergunta do usuário: ${question}`;

      const response = await openai.chat.completions.create({
        model: "gpt-4o-mini",
        messages: [
          { role: "system", content: systemPrompt },
          { role: "user", content: userPrompt }
        ],
        response_format: { type: "json_object" },
        max_tokens: 2000,
      });

      const content = response.choices[0]?.message?.content || "{}";
      let result;
      try {
        result = JSON.parse(content);
      } catch {
        result = { answer: content, insights: [], suggestedChart: null };
      }

      res.json({
        success: true,
        question,
        datasetId,
        datasetName: dataset.name,
        pandasAnalysis: pandasAnalysis ? {
          rowCount: pandasAnalysis.row_count,
          insights: pandasAnalysis.insights,
          suggestedCharts: pandasAnalysis.suggested_charts,
        } : null,
        ...result,
      });
    } catch (error: any) {
      console.error("AI Analysis error:", error);
      res.status(500).json({ error: error.message || "Falha na análise" });
    }
  });

  app.post("/api/bi/ai-create-chart", async (req: Request, res: Response) => {
    try {
      if (!req.isAuthenticated()) {
        return res.status(401).json({ error: "Not authenticated" });
      }

      const { datasetId, chartConfig } = req.body;
      const userId = req.user!.id;

      if (!datasetId || !chartConfig) {
        return res.status(400).json({ error: "Dados inválidos" });
      }

      const [chart] = await db.insert(biCharts).values({
        userId,
        datasetId,
        name: chartConfig.title || "Gráfico IA",
        chartType: chartConfig.type || "bar",
        config: JSON.stringify({
          xAxis: chartConfig.xAxis,
          yAxis: chartConfig.yAxis,
          groupBy: chartConfig.groupBy,
          aggregation: chartConfig.aggregation,
          colors: ["#c89b3c", "#4caf50", "#2196f3", "#ff9800", "#9c27b0"],
        }),
      }).returning();

      res.json({ success: true, chart });
    } catch (error: any) {
      console.error("Create chart error:", error);
      res.status(500).json({ error: error.message || "Falha ao criar gráfico" });
    }
  });
}
