import { Router, Request, Response } from "express";
import { db } from "../../db/index";
import { eq, desc, and, or, isNull, inArray, sql } from "drizzle-orm";
import { users, profiles, crmPartners, crmClients, tenants, tenantPlans, partnerClients, partnerCommissions, insertTenantSchema, insertTenantPlanSchema, insertPartnerClientSchema } from "@shared/schema";
import fs from "fs";
import path from "path";

const router = Router();

// Helper: Retorna IDs de tenants que o usuário pode acessar
async function getAllowedTenantIds(user: any): Promise<number[] | null> {
  // null = acesso total (master)
  if (!user.tenantId || user.tenantType === "master") return null;
  
  if (user.tenantType === "partner") {
    // Partner vê seu próprio tenant + clientes vinculados
    const clientRelations = await db.select({ clientId: partnerClients.clientId })
      .from(partnerClients)
      .where(eq(partnerClients.partnerId, user.tenantId));
    return [user.tenantId, ...clientRelations.map(r => r.clientId)];
  }
  
  // Client vê apenas seu próprio tenant
  return [user.tenantId];
}

// Helper: Verifica se usuário pode acessar um tenant específico
async function canAccessTenant(user: any, tenantId: number): Promise<boolean> {
  const allowed = await getAllowedTenantIds(user);
  if (allowed === null) return true; // Master pode tudo
  return allowed.includes(tenantId);
}

router.use((req: Request, res: Response, next) => {
  if (!req.isAuthenticated()) {
    return res.status(401).json({ error: "Não autorizado" });
  }
  const user = req.user as any;
  if (user.role !== "admin") {
    return res.status(403).json({ error: "Acesso negado. Apenas administradores." });
  }
  next();
});

router.get("/profiles", async (req: Request, res: Response) => {
  try {
    const allProfiles = await db.select().from(profiles).orderBy(profiles.name);
    res.json(allProfiles);
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

router.post("/profiles", async (req: Request, res: Response) => {
  try {
    const { name, description, type, allowedModules, status } = req.body;
    const [profile] = await db.insert(profiles).values({
      name,
      description,
      type: type || "custom",
      allowedModules: allowedModules || [],
      status: status || "active",
    }).returning();
    res.status(201).json(profile);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

router.patch("/profiles/:id", async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id);
    const { name, description, allowedModules, status } = req.body;
    const [profile] = await db.update(profiles)
      .set({ name, description, allowedModules, status, updatedAt: new Date() })
      .where(eq(profiles.id, id))
      .returning();
    if (!profile) return res.status(404).json({ error: "Perfil não encontrado" });
    res.json(profile);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

router.delete("/profiles/:id", async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id);
    const [profile] = await db.select().from(profiles).where(eq(profiles.id, id));
    if (!profile) return res.status(404).json({ error: "Perfil não encontrado" });
    if (profile.isSystem === 1) {
      return res.status(400).json({ error: "Não é possível excluir perfis do sistema" });
    }
    await db.delete(profiles).where(eq(profiles.id, id));
    res.status(204).send();
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

router.get("/users", async (req: Request, res: Response) => {
  try {
    const allUsers = await db.select({
      id: users.id,
      username: users.username,
      name: users.name,
      email: users.email,
      role: users.role,
      profileId: users.profileId,
      partnerId: users.partnerId,
      status: users.status,
      lastLoginAt: users.lastLoginAt,
      createdAt: users.createdAt,
    }).from(users).orderBy(users.name);
    
    const usersWithProfile = await Promise.all(allUsers.map(async (user) => {
      let profile = null;
      let partner = null;
      if (user.profileId) {
        const [p] = await db.select().from(profiles).where(eq(profiles.id, user.profileId));
        profile = p;
      }
      if (user.partnerId) {
        const [pt] = await db.select().from(crmPartners).where(eq(crmPartners.id, user.partnerId));
        partner = pt;
      }
      return { ...user, profile, partner };
    }));
    
    res.json(usersWithProfile);
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

router.patch("/users/:id", async (req: Request, res: Response) => {
  try {
    const id = req.params.id;
    const { name, email, role, profileId, partnerId, status } = req.body;
    const [user] = await db.update(users)
      .set({ name, email, role, profileId, partnerId, status })
      .where(eq(users.id, id))
      .returning();
    if (!user) return res.status(404).json({ error: "Usuário não encontrado" });
    res.json(user);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

router.patch("/users/:id/status", async (req: Request, res: Response) => {
  try {
    const id = req.params.id;
    const { status } = req.body;
    const [user] = await db.update(users)
      .set({ status })
      .where(eq(users.id, id))
      .returning();
    if (!user) return res.status(404).json({ error: "Usuário não encontrado" });
    res.json(user);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

router.patch("/partners/:id/status", async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id);
    const { status } = req.body;
    const [partner] = await db.update(crmPartners)
      .set({ status, updatedAt: new Date() })
      .where(eq(crmPartners.id, id))
      .returning();
    if (!partner) return res.status(404).json({ error: "Parceiro não encontrado" });
    res.json(partner);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

router.patch("/clients/:id/status", async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id);
    const { status } = req.body;
    const [client] = await db.update(crmClients)
      .set({ status, updatedAt: new Date() })
      .where(eq(crmClients.id, id))
      .returning();
    if (!client) return res.status(404).json({ error: "Cliente não encontrado" });
    res.json(client);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

router.get("/stats", async (req: Request, res: Response) => {
  try {
    const [allUsers] = await db.select({ count: db.$count(users) }).from(users);
    const [activeUsers] = await db.select({ count: db.$count(users) }).from(users).where(eq(users.status, "active"));
    const [allProfiles] = await db.select({ count: db.$count(profiles) }).from(profiles);
    const [allPartners] = await db.select({ count: db.$count(crmPartners) }).from(crmPartners);
    const [activePartners] = await db.select({ count: db.$count(crmPartners) }).from(crmPartners).where(eq(crmPartners.status, "active"));
    const [allClients] = await db.select({ count: db.$count(crmClients) }).from(crmClients);
    const [activeClients] = await db.select({ count: db.$count(crmClients) }).from(crmClients).where(eq(crmClients.status, "active"));
    
    res.json({
      users: { total: allUsers.count, active: activeUsers.count },
      profiles: { total: allProfiles.count },
      partners: { total: allPartners.count, active: activePartners.count },
      clients: { total: allClients.count, active: activeClients.count },
    });
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

router.get("/libraries", async (req: Request, res: Response) => {
  try {
    const packageJsonPath = path.join(process.cwd(), "package.json");
    const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
    
    const dependencies = Object.entries(packageJson.dependencies || {}).map(([name, version]) => ({
      name,
      version: String(version).replace(/^\^|~/, ""),
      type: "production",
      category: categorizePackage(name),
    }));
    
    const devDependencies = Object.entries(packageJson.devDependencies || {}).map(([name, version]) => ({
      name,
      version: String(version).replace(/^\^|~/, ""),
      type: "development",
      category: categorizePackage(name),
    }));
    
    res.json({
      nodejs: {
        dependencies,
        devDependencies,
        total: dependencies.length + devDependencies.length,
      },
      python: {
        dependencies: [],
        total: 0,
        note: "Python microservices planejados para próximas versões",
      },
    });
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

function categorizePackage(name: string): string {
  if (name.includes("react") || name.includes("radix") || name.includes("tailwind")) return "UI/Frontend";
  if (name.includes("express") || name.includes("passport") || name.includes("session")) return "Backend/Auth";
  if (name.includes("drizzle") || name.includes("pg") || name.includes("connect-pg")) return "Database";
  if (name.includes("socket") || name.includes("ws") || name.includes("whatsapp")) return "Real-time/Comunicação";
  if (name.includes("openai") || name.includes("ai")) return "AI/ML";
  if (name.includes("zod") || name.includes("hook-form")) return "Validação/Forms";
  if (name.includes("vite") || name.includes("typescript") || name.includes("tsx") || name.includes("esbuild")) return "Build/Dev Tools";
  if (name.includes("lucide") || name.includes("framer")) return "Icons/Animações";
  if (name.includes("pdf") || name.includes("docx") || name.includes("csv") || name.includes("zip")) return "Documentos/Arquivos";
  if (name.includes("recharts") || name.includes("chart")) return "Visualização";
  if (name.includes("date") || name.includes("day-picker")) return "Data/Tempo";
  return "Utilitários";
}

// ==========================================
// MULTI-TENANT MANAGEMENT ROUTES
// ==========================================

// GET /api/admin/tenants - List all tenants with hierarchy
router.get("/tenants", async (req: Request, res: Response) => {
  try {
    const { type } = req.query;
    const user = req.user as any;
    
    const allTenants = await db.select().from(tenants).orderBy(desc(tenants.createdAt));
    
    // Filtrar por tenant do usuário
    let filteredByAccess = allTenants;
    if (user.tenantType === "partner") {
      // Partner vê apenas seu próprio tenant e seus clientes
      const clientRelations = await db.select().from(partnerClients)
        .where(eq(partnerClients.partnerId, user.tenantId));
      const clientIds = clientRelations.map(r => r.clientId);
      filteredByAccess = allTenants.filter(t => 
        t.id === user.tenantId || clientIds.includes(t.id)
      );
    } else if (user.tenantType === "client") {
      // Client vê apenas seu próprio tenant
      filteredByAccess = allTenants.filter(t => t.id === user.tenantId);
    }
    // Master (tenantType === "master") vê todos
    
    // Filter by type if specified
    const filteredTenants = type 
      ? filteredByAccess.filter(t => t.tenantType === type)
      : filteredByAccess;
    
    // Add parent tenant info
    const tenantsWithParent = await Promise.all(filteredTenants.map(async (tenant) => {
      let parentTenant = null;
      if (tenant.parentTenantId) {
        const [parent] = await db.select().from(tenants).where(eq(tenants.id, tenant.parentTenantId));
        parentTenant = parent ? { id: parent.id, name: parent.name, tenantType: parent.tenantType } : null;
      }
      
      // Count child tenants
      const childTenants = allTenants.filter(t => t.parentTenantId === tenant.id);
      
      return { ...tenant, parentTenant, childCount: childTenants.length };
    }));
    
    res.json(tenantsWithParent);
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

// POST /api/admin/tenants - Create new tenant
router.post("/tenants", async (req: Request, res: Response) => {
  try {
    const validated = insertTenantSchema.parse(req.body);
    const [tenant] = await db.insert(tenants).values(validated).returning();
    res.status(201).json(tenant);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

// PATCH /api/admin/tenants/:id - Update tenant
router.patch("/tenants/:id", async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id);
    const user = req.user as any;
    
    // Verificar permissão de acesso
    if (!await canAccessTenant(user, id)) {
      return res.status(403).json({ error: "Sem permissão para modificar este tenant" });
    }
    
    const { name, email, phone, plan, status, tenantType, parentTenantId, partnerCode, commissionRate, maxUsers, maxStorageMb, features, billingEmail, trialEndsAt } = req.body;
    
    const [tenant] = await db.update(tenants)
      .set({ 
        name, email, phone, plan, status, tenantType, parentTenantId, partnerCode, 
        commissionRate, maxUsers, maxStorageMb, features, billingEmail, trialEndsAt,
        updatedAt: new Date() 
      })
      .where(eq(tenants.id, id))
      .returning();
    
    if (!tenant) return res.status(404).json({ error: "Tenant não encontrado" });
    res.json(tenant);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

// DELETE /api/admin/tenants/:id - Delete tenant
router.delete("/tenants/:id", async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id);
    const user = req.user as any;
    
    // Apenas master pode excluir tenants
    if (user.tenantType !== "master") {
      return res.status(403).json({ error: "Apenas master pode excluir tenants" });
    }
    
    const [tenant] = await db.select().from(tenants).where(eq(tenants.id, id));
    if (!tenant) return res.status(404).json({ error: "Tenant não encontrado" });
    if (tenant.tenantType === "master") {
      return res.status(400).json({ error: "Não é possível excluir o tenant master" });
    }
    await db.delete(tenants).where(eq(tenants.id, id));
    res.status(204).send();
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

// GET /api/admin/tenants/hierarchy - Get hierarchy tree
router.get("/tenants/hierarchy", async (req: Request, res: Response) => {
  try {
    const user = req.user as any;
    const allowedIds = await getAllowedTenantIds(user);
    
    let allTenants = await db.select().from(tenants).orderBy(tenants.name);
    
    // Filtrar por acesso do usuário
    if (allowedIds !== null) {
      allTenants = allTenants.filter(t => allowedIds.includes(t.id));
    }
    
    // Build hierarchy tree
    const buildTree = (parentId: number | null): any[] => {
      return allTenants
        .filter(t => t.parentTenantId === parentId)
        .map(t => ({
          ...t,
          children: buildTree(t.id)
        }));
    };
    
    // Start from master tenants (no parent) or user's tenant
    const hierarchy = allowedIds === null 
      ? buildTree(null) 
      : allTenants.map(t => ({ ...t, children: [] }));
    res.json(hierarchy);
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

// ==========================================
// TENANT PLANS ROUTES
// ==========================================

// GET /api/admin/plans - List all plans
router.get("/plans", async (req: Request, res: Response) => {
  try {
    const allPlans = await db.select().from(tenantPlans).orderBy(tenantPlans.sortOrder);
    res.json(allPlans);
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

// POST /api/admin/plans - Create new plan
router.post("/plans", async (req: Request, res: Response) => {
  try {
    const validated = insertTenantPlanSchema.parse(req.body);
    const [plan] = await db.insert(tenantPlans).values(validated).returning();
    res.status(201).json(plan);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

// PATCH /api/admin/plans/:id - Update plan
router.patch("/plans/:id", async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id);
    const { name, description, maxUsers, maxStorageMb, features, monthlyPrice, yearlyPrice, trialDays, isActive, sortOrder } = req.body;
    
    const [plan] = await db.update(tenantPlans)
      .set({ name, description, maxUsers, maxStorageMb, features, monthlyPrice, yearlyPrice, trialDays, isActive, sortOrder })
      .where(eq(tenantPlans.id, id))
      .returning();
    
    if (!plan) return res.status(404).json({ error: "Plano não encontrado" });
    res.json(plan);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

// DELETE /api/admin/plans/:id - Delete plan
router.delete("/plans/:id", async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id);
    await db.delete(tenantPlans).where(eq(tenantPlans.id, id));
    res.status(204).send();
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

// ==========================================
// PARTNER-CLIENT RELATIONSHIPS
// ==========================================

// GET /api/admin/partner-clients - List partner-client relationships
router.get("/partner-clients", async (req: Request, res: Response) => {
  try {
    const user = req.user as any;
    const allowedIds = await getAllowedTenantIds(user);
    
    let relationships = await db.select().from(partnerClients).orderBy(desc(partnerClients.startedAt));
    
    // Filtrar por acesso do usuário
    if (allowedIds !== null) {
      relationships = relationships.filter(r => 
        allowedIds.includes(r.partnerId) || allowedIds.includes(r.clientId)
      );
    }
    
    // Add partner and client info
    const withDetails = await Promise.all(relationships.map(async (rel) => {
      const [partner] = await db.select().from(tenants).where(eq(tenants.id, rel.partnerId));
      const [client] = await db.select().from(tenants).where(eq(tenants.id, rel.clientId));
      return {
        ...rel,
        partner: partner ? { id: partner.id, name: partner.name } : null,
        client: client ? { id: client.id, name: client.name } : null,
      };
    }));
    
    res.json(withDetails);
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

// POST /api/admin/partner-clients - Create partner-client relationship
router.post("/partner-clients", async (req: Request, res: Response) => {
  try {
    const validated = insertPartnerClientSchema.parse(req.body);
    const [relationship] = await db.insert(partnerClients).values(validated).returning();
    res.status(201).json(relationship);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

// ==========================================
// PARTNER COMMISSIONS
// ==========================================

// GET /api/admin/commissions - List all commissions
router.get("/commissions", async (req: Request, res: Response) => {
  try {
    const user = req.user as any;
    const allowedIds = await getAllowedTenantIds(user);
    const { partnerId, status } = req.query;
    
    let allCommissions = await db.select().from(partnerCommissions).orderBy(desc(partnerCommissions.createdAt));
    
    // Filtrar por acesso do usuário
    if (allowedIds !== null) {
      allCommissions = allCommissions.filter(c => 
        allowedIds.includes(c.partnerId) || allowedIds.includes(c.clientId)
      );
    }
    
    if (partnerId) {
      allCommissions = allCommissions.filter(c => c.partnerId === parseInt(partnerId as string));
    }
    if (status) {
      allCommissions = allCommissions.filter(c => c.status === status);
    }
    
    // Add partner and client info
    const withDetails = await Promise.all(allCommissions.map(async (comm) => {
      const [partner] = await db.select().from(tenants).where(eq(tenants.id, comm.partnerId));
      const [client] = await db.select().from(tenants).where(eq(tenants.id, comm.clientId));
      return {
        ...comm,
        partner: partner ? { id: partner.id, name: partner.name } : null,
        client: client ? { id: client.id, name: client.name } : null,
      };
    }));
    
    res.json(withDetails);
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

// PATCH /api/admin/commissions/:id/approve - Approve commission
router.patch("/commissions/:id/approve", async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id);
    const [commission] = await db.update(partnerCommissions)
      .set({ status: "approved", approvedAt: new Date() })
      .where(eq(partnerCommissions.id, id))
      .returning();
    
    if (!commission) return res.status(404).json({ error: "Comissão não encontrada" });
    res.json(commission);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

// PATCH /api/admin/commissions/:id/pay - Mark commission as paid
router.patch("/commissions/:id/pay", async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id);
    const { paymentReference } = req.body;
    
    const [commission] = await db.update(partnerCommissions)
      .set({ status: "paid", paidAt: new Date(), paymentReference })
      .where(eq(partnerCommissions.id, id))
      .returning();
    
    if (!commission) return res.status(404).json({ error: "Comissão não encontrada" });
    res.json(commission);
  } catch (error: any) {
    res.status(400).json({ error: error.message });
  }
});

// GET /api/admin/tenants/stats - Tenant statistics
router.get("/tenants/stats", async (req: Request, res: Response) => {
  try {
    const allTenants = await db.select().from(tenants);
    
    const stats = {
      total: allTenants.length,
      byType: {
        master: allTenants.filter(t => t.tenantType === "master").length,
        partner: allTenants.filter(t => t.tenantType === "partner").length,
        client: allTenants.filter(t => t.tenantType === "client").length,
      },
      byStatus: {
        active: allTenants.filter(t => t.status === "active").length,
        trial: allTenants.filter(t => t.status === "trial").length,
        suspended: allTenants.filter(t => t.status === "suspended").length,
        cancelled: allTenants.filter(t => t.status === "cancelled").length,
      }
    };
    
    res.json(stats);
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

export default router;
