import { db } from "./db";
import {
  users,
  plans,
  planSteps,
  notifications,
  aiLogs,
  savedAiResponses,
  type User,
  type UpsertUser,
  type Plan,
  type InsertPlan,
  type PlanStep,
  type InsertPlanStep,
  type Notification,
  type InsertNotification,
  type AiLog,
  type InsertAiLog,
  type SavedAiResponse,
  type InsertSavedAiResponse,
} from "@shared/schema";
import { eq, desc, and } from "drizzle-orm";

export interface IStorage {
  // User operations - required for Replit Auth
  getUser(id: string): Promise<User | undefined>;
  upsertUser(user: UpsertUser): Promise<User>;

  // Plan operations
  getUserPlans(userId: string): Promise<Plan[]>;
  getPlan(id: string): Promise<Plan | undefined>;
  createPlan(plan: InsertPlan): Promise<Plan>;
  updatePlan(
    id: string,
    updates: Partial<InsertPlan>
  ): Promise<Plan | undefined>;
  deletePlan(id: string): Promise<void>;
  updatePlanProgress(planId: string): Promise<void>;

  // Step operations
  getPlanSteps(planId: string): Promise<PlanStep[]>;
  getStep(id: string): Promise<PlanStep | undefined>;
  createStep(step: InsertPlanStep): Promise<PlanStep>;
  updateStep(
    id: string,
    updates: Partial<InsertPlanStep>
  ): Promise<PlanStep | undefined>;
  deleteStep(id: string): Promise<void>;

  // Notification operations
  getUserNotifications(userId: string): Promise<Notification[]>;
  createNotification(notification: InsertNotification): Promise<Notification>;
  markNotificationSeen(id: string): Promise<void>;
  deleteNotification(id: string): Promise<void>;

  // AI log operations
  createAiLog(log: InsertAiLog): Promise<AiLog>;
  getUserAiUsageCount(userId: string): Promise<number>;

  // Saved AI response operations
  createSavedAiResponse(response: InsertSavedAiResponse): Promise<SavedAiResponse>;
  getUserSavedAiResponses(userId: string): Promise<SavedAiResponse[]>;
  getPlanSavedAiResponses(planId: string): Promise<SavedAiResponse[]>;
  deleteSavedAiResponse(id: string): Promise<void>;

  // Admin operations
  getAllUsers(): Promise<User[]>;
  getAllPlansWithUsers(): Promise<any[]>;
}

export class DbStorage implements IStorage {
  // User operations - required for Replit Auth
  async getUser(id: string): Promise<User | undefined> {
    const result = await db.select().from(users).where(eq(users.id, id)).limit(1);
    return result[0];
  }

  async upsertUser(userData: UpsertUser): Promise<User> {
    const [user] = await db
      .insert(users)
      .values(userData)
      .onConflictDoUpdate({
        target: users.id,
        set: {
          ...userData,
          updatedAt: new Date(),
        },
      })
      .returning();
    return user;
  }

  // Plan operations
  async getUserPlans(userId: string): Promise<Plan[]> {
    return await db
      .select()
      .from(plans)
      .where(eq(plans.userId, userId))
      .orderBy(desc(plans.updatedAt));
  }

  async getPlan(id: string): Promise<Plan | undefined> {
    const result = await db
      .select()
      .from(plans)
      .where(eq(plans.id, id))
      .limit(1);
    return result[0];
  }

  async createPlan(plan: InsertPlan): Promise<Plan> {
    const result = await db.insert(plans).values(plan).returning();
    return result[0];
  }

  async updatePlan(
    id: string,
    updates: Partial<InsertPlan>
  ): Promise<Plan | undefined> {
    const result = await db
      .update(plans)
      .set({ ...updates, updatedAt: new Date() })
      .where(eq(plans.id, id))
      .returning();
    return result[0];
  }

  async deletePlan(id: string): Promise<void> {
    await db.delete(plans).where(eq(plans.id, id));
  }

  async updatePlanProgress(planId: string): Promise<void> {
    const steps = await this.getPlanSteps(planId);
    const completedSteps = steps.filter((s) => s.status === "completed").length;
    const progress = steps.length > 0 ? (completedSteps / steps.length) * 100 : 0;

    await db
      .update(plans)
      .set({ progressPercent: progress, updatedAt: new Date() })
      .where(eq(plans.id, planId));
  }

  // Step operations
  async getPlanSteps(planId: string): Promise<PlanStep[]> {
    return await db
      .select()
      .from(planSteps)
      .where(eq(planSteps.planId, planId))
      .orderBy(planSteps.orderIndex);
  }

  async getStep(id: string): Promise<PlanStep | undefined> {
    const result = await db
      .select()
      .from(planSteps)
      .where(eq(planSteps.id, id))
      .limit(1);
    return result[0];
  }

  async createStep(step: InsertPlanStep): Promise<PlanStep> {
    const result = await db.insert(planSteps).values(step).returning();
    await this.updatePlanProgress(step.planId);
    return result[0];
  }

  async updateStep(
    id: string,
    updates: Partial<InsertPlanStep>
  ): Promise<PlanStep | undefined> {
    const result = await db
      .update(planSteps)
      .set({ ...updates, updatedAt: new Date() })
      .where(eq(planSteps.id, id))
      .returning();

    if (result[0]) {
      await this.updatePlanProgress(result[0].planId);
    }

    return result[0];
  }

  async deleteStep(id: string): Promise<void> {
    const step = await db
      .select()
      .from(planSteps)
      .where(eq(planSteps.id, id))
      .limit(1);
    await db.delete(planSteps).where(eq(planSteps.id, id));

    if (step[0]) {
      await this.updatePlanProgress(step[0].planId);
    }
  }

  // Notification operations
  async getUserNotifications(userId: string): Promise<Notification[]> {
    return await db
      .select()
      .from(notifications)
      .where(eq(notifications.userId, userId))
      .orderBy(desc(notifications.createdAt));
  }

  async createNotification(
    notification: InsertNotification
  ): Promise<Notification> {
    const result = await db
      .insert(notifications)
      .values(notification)
      .returning();
    return result[0];
  }

  async markNotificationSeen(id: string): Promise<void> {
    await db
      .update(notifications)
      .set({ seen: true })
      .where(eq(notifications.id, id));
  }

  async deleteNotification(id: string): Promise<void> {
    await db.delete(notifications).where(eq(notifications.id, id));
  }

  // AI log operations
  async createAiLog(log: InsertAiLog): Promise<AiLog> {
    const result = await db.insert(aiLogs).values(log).returning();
    return result[0];
  }

  async getUserAiUsageCount(userId: string): Promise<number> {
    const result = await db
      .select()
      .from(aiLogs)
      .where(eq(aiLogs.userId, userId));
    return result.length;
  }

  // Saved AI response operations
  async createSavedAiResponse(response: InsertSavedAiResponse): Promise<SavedAiResponse> {
    const result = await db.insert(savedAiResponses).values(response).returning();
    return result[0];
  }

  async getUserSavedAiResponses(userId: string): Promise<SavedAiResponse[]> {
    return await db
      .select()
      .from(savedAiResponses)
      .where(eq(savedAiResponses.userId, userId))
      .orderBy(desc(savedAiResponses.createdAt));
  }

  async getPlanSavedAiResponses(planId: string): Promise<SavedAiResponse[]> {
    return await db
      .select()
      .from(savedAiResponses)
      .where(eq(savedAiResponses.planId, planId))
      .orderBy(desc(savedAiResponses.createdAt));
  }

  async deleteSavedAiResponse(id: string): Promise<void> {
    await db.delete(savedAiResponses).where(eq(savedAiResponses.id, id));
  }

  // Admin operations
  async getAllUsers(): Promise<User[]> {
    return await db.select().from(users).orderBy(desc(users.createdAt));
  }

  async getAllPlansWithUsers(): Promise<any[]> {
    return await db
      .select({
        plan: plans,
        user: users,
      })
      .from(plans)
      .leftJoin(users, eq(plans.userId, users.id))
      .orderBy(desc(plans.updatedAt));
  }
}

export const storage = new DbStorage();
