import {
  routers,
  networkLogs,
  detections,
  whitelist,
  trainingHistory,
  networkAnalytics,
  type Router,
  type InsertRouter,
  type NetworkLog,
  type InsertNetworkLog,
  type Detection,
  type InsertDetection,
  type Whitelist,
  type InsertWhitelist,
  type TrainingHistory,
  type InsertTrainingHistory,
  type NetworkAnalytics,
} from "@shared/schema";
import { db } from "./db";
import { eq, desc, and, gte, sql, inArray } from "drizzle-orm";

export interface IStorage {
  // Routers
  getAllRouters(): Promise<Router[]>;
  getRouterById(id: string): Promise<Router | undefined>;
  createRouter(router: InsertRouter): Promise<Router>;
  updateRouter(id: string, router: Partial<InsertRouter>): Promise<Router | undefined>;
  deleteRouter(id: string): Promise<boolean>;

  // Network Logs
  getRecentLogs(limit: number): Promise<NetworkLog[]>;
  getLogsByIp(sourceIp: string, limit: number): Promise<NetworkLog[]>;
  createLog(log: InsertNetworkLog): Promise<NetworkLog>;
  getLogsForTraining(limit: number, minTimestamp?: Date): Promise<NetworkLog[]>;

  // Detections
  getAllDetections(limit: number): Promise<Detection[]>;
  getDetectionByIp(sourceIp: string): Promise<Detection | undefined>;
  createDetection(detection: InsertDetection): Promise<Detection>;
  updateDetection(id: string, detection: Partial<InsertDetection>): Promise<Detection | undefined>;
  getUnblockedDetections(): Promise<Detection[]>;

  // Whitelist
  getAllWhitelist(): Promise<Whitelist[]>;
  getWhitelistByIp(ipAddress: string): Promise<Whitelist | undefined>;
  createWhitelist(whitelist: InsertWhitelist): Promise<Whitelist>;
  deleteWhitelist(id: string): Promise<boolean>;
  isWhitelisted(ipAddress: string): Promise<boolean>;

  // Training History
  getTrainingHistory(limit: number): Promise<TrainingHistory[]>;
  createTrainingHistory(history: InsertTrainingHistory): Promise<TrainingHistory>;
  getLatestTraining(): Promise<TrainingHistory | undefined>;

  // Network Analytics
  getAnalyticsByDateRange(startDate: Date, endDate: Date, hourly?: boolean): Promise<NetworkAnalytics[]>;
  getRecentAnalytics(days: number, hourly?: boolean): Promise<NetworkAnalytics[]>;

  // System
  testConnection(): Promise<boolean>;
}

export class DatabaseStorage implements IStorage {
  // Routers
  async getAllRouters(): Promise<Router[]> {
    return await db.select().from(routers).orderBy(desc(routers.createdAt));
  }

  async getRouterById(id: string): Promise<Router | undefined> {
    const [router] = await db.select().from(routers).where(eq(routers.id, id));
    return router || undefined;
  }

  async createRouter(insertRouter: InsertRouter): Promise<Router> {
    const [router] = await db.insert(routers).values(insertRouter).returning();
    return router;
  }

  async updateRouter(id: string, updateData: Partial<InsertRouter>): Promise<Router | undefined> {
    const [router] = await db
      .update(routers)
      .set(updateData)
      .where(eq(routers.id, id))
      .returning();
    return router || undefined;
  }

  async deleteRouter(id: string): Promise<boolean> {
    const result = await db.delete(routers).where(eq(routers.id, id));
    return result.rowCount !== null && result.rowCount > 0;
  }

  // Network Logs
  async getRecentLogs(limit: number): Promise<NetworkLog[]> {
    return await db
      .select()
      .from(networkLogs)
      .orderBy(desc(networkLogs.timestamp))
      .limit(limit);
  }

  async getLogsByIp(sourceIp: string, limit: number): Promise<NetworkLog[]> {
    return await db
      .select()
      .from(networkLogs)
      .where(eq(networkLogs.sourceIp, sourceIp))
      .orderBy(desc(networkLogs.timestamp))
      .limit(limit);
  }

  async createLog(insertLog: InsertNetworkLog): Promise<NetworkLog> {
    const [log] = await db.insert(networkLogs).values(insertLog).returning();
    return log;
  }

  async getLogsForTraining(limit: number, minTimestamp?: Date): Promise<NetworkLog[]> {
    const conditions = minTimestamp
      ? and(gte(networkLogs.timestamp, minTimestamp))
      : undefined;

    return await db
      .select()
      .from(networkLogs)
      .where(conditions)
      .orderBy(desc(networkLogs.timestamp))
      .limit(limit);
  }

  // Detections
  async getAllDetections(limit: number): Promise<Detection[]> {
    return await db
      .select()
      .from(detections)
      .orderBy(desc(detections.detectedAt))
      .limit(limit);
  }

  async getDetectionByIp(sourceIp: string): Promise<Detection | undefined> {
    const [detection] = await db
      .select()
      .from(detections)
      .where(eq(detections.sourceIp, sourceIp))
      .orderBy(desc(detections.detectedAt))
      .limit(1);
    return detection || undefined;
  }

  async createDetection(insertDetection: InsertDetection): Promise<Detection> {
    const [detection] = await db
      .insert(detections)
      .values(insertDetection)
      .returning();
    return detection;
  }

  async updateDetection(
    id: string,
    updateData: Partial<InsertDetection>
  ): Promise<Detection | undefined> {
    const [detection] = await db
      .update(detections)
      .set(updateData)
      .where(eq(detections.id, id))
      .returning();
    return detection || undefined;
  }

  async getUnblockedDetections(): Promise<Detection[]> {
    return await db
      .select()
      .from(detections)
      .where(eq(detections.blocked, false))
      .orderBy(desc(detections.riskScore));
  }

  // Whitelist
  async getAllWhitelist(): Promise<Whitelist[]> {
    return await db
      .select()
      .from(whitelist)
      .where(eq(whitelist.active, true))
      .orderBy(desc(whitelist.createdAt));
  }

  async getWhitelistByIp(ipAddress: string): Promise<Whitelist | undefined> {
    const [item] = await db
      .select()
      .from(whitelist)
      .where(and(eq(whitelist.ipAddress, ipAddress), eq(whitelist.active, true)));
    return item || undefined;
  }

  async createWhitelist(insertWhitelist: InsertWhitelist): Promise<Whitelist> {
    const [item] = await db.insert(whitelist).values(insertWhitelist).returning();
    return item;
  }

  async deleteWhitelist(id: string): Promise<boolean> {
    const result = await db.delete(whitelist).where(eq(whitelist.id, id));
    return result.rowCount !== null && result.rowCount > 0;
  }

  async isWhitelisted(ipAddress: string): Promise<boolean> {
    const item = await this.getWhitelistByIp(ipAddress);
    return item !== undefined;
  }

  // Training History
  async getTrainingHistory(limit: number): Promise<TrainingHistory[]> {
    return await db
      .select()
      .from(trainingHistory)
      .orderBy(desc(trainingHistory.trainedAt))
      .limit(limit);
  }

  async createTrainingHistory(insertHistory: InsertTrainingHistory): Promise<TrainingHistory> {
    const [history] = await db
      .insert(trainingHistory)
      .values(insertHistory)
      .returning();
    return history;
  }

  async getLatestTraining(): Promise<TrainingHistory | undefined> {
    const [history] = await db
      .select()
      .from(trainingHistory)
      .orderBy(desc(trainingHistory.trainedAt))
      .limit(1);
    return history || undefined;
  }

  // Network Analytics
  async getAnalyticsByDateRange(startDate: Date, endDate: Date, hourly: boolean = false): Promise<NetworkAnalytics[]> {
    const hourCondition = hourly 
      ? sql`hour IS NOT NULL`
      : sql`hour IS NULL`;
    
    return await db
      .select()
      .from(networkAnalytics)
      .where(
        and(
          gte(networkAnalytics.date, startDate),
          sql`${networkAnalytics.date} <= ${endDate}`,
          hourCondition
        )
      )
      .orderBy(desc(networkAnalytics.date), desc(networkAnalytics.hour));
  }

  async getRecentAnalytics(days: number, hourly: boolean = false): Promise<NetworkAnalytics[]> {
    const startDate = new Date();
    startDate.setDate(startDate.getDate() - days);
    
    return this.getAnalyticsByDateRange(startDate, new Date(), hourly);
  }

  async testConnection(): Promise<boolean> {
    try {
      await db.execute(sql`SELECT 1`);
      return true;
    } catch (error) {
      console.error('[DB ERROR] Connection test failed:', error);
      return false;
    }
  }
}

export const storage = new DatabaseStorage();
