import { 
  settlements, expenses, directPayments, appSettings, users,
  type Settlement, type InsertSettlement, 
  type Expense, type InsertExpense,
  type DirectPayment, type InsertDirectPayment,
  type SettlementWithDetails,
  type AppSetting, type AppSettingsMap,
  type User, type InsertUser,
} from "@shared/schema";
import { db } from "./db";
import { eq, desc } from "drizzle-orm";

// Default settings seeded if missing
export const DEFAULT_SETTINGS: AppSettingsMap = {
  party_a_name: 'Phoenix',
  party_b_name: 'Broduer',
  party_c_name: 'Envy',
  party_d_name: 'Boney',
  cutoff_date: '2026-02-08',
  before_party_a_rate: '0.30',
  before_party_b_rate: '0.65',
  before_party_c_rate: '0.05',
  after_party_a_rate: '0.33',
  after_party_b_rate: '0.62',
  after_party_c_rate: '0.05',
  boney_rate: '0.05',
};

export interface IStorage {
  // Settlements
  createSettlement(settlement: any, expensesList: InsertExpense[], directPaymentsList: InsertDirectPayment[]): Promise<Settlement>;
  getSettlements(): Promise<Settlement[]>;
  getSettlement(id: number): Promise<SettlementWithDetails | undefined>;
  updateSettlement(id: number, settlement: any, expensesList: InsertExpense[], directPaymentsList: InsertDirectPayment[]): Promise<Settlement>;
  deleteSettlement(id: number): Promise<void>;
  // Settings
  getSettings(): Promise<AppSettingsMap>;
  upsertSettings(settings: AppSettingsMap): Promise<AppSettingsMap>;
  // Users
  getUsers(): Promise<User[]>;
  createUser(user: InsertUser): Promise<User>;
  updateUser(id: number, user: Partial<InsertUser>): Promise<User>;
  deleteUser(id: number): Promise<void>;
}

export class DatabaseStorage implements IStorage {
  async createSettlement(insertSettlement: any, expensesList: InsertExpense[], directPaymentsList: InsertDirectPayment[]): Promise<Settlement> {
    const [settlement] = await db.insert(settlements).values(insertSettlement).returning();
    
    if (expensesList.length > 0) {
      await db.insert(expenses).values(
        expensesList.map(e => ({ ...e, settlementId: settlement.id }))
      );
    }

    if (directPaymentsList.length > 0) {
      await db.insert(directPayments).values(
        directPaymentsList.map(dp => ({ ...dp, settlementId: settlement.id }))
      );
    }
    
    return settlement;
  }

  async getSettlements(): Promise<Settlement[]> {
    return await db.select().from(settlements).orderBy(desc(settlements.weekEndDate));
  }

  async getSettlement(id: number): Promise<SettlementWithDetails | undefined> {
    const [settlement] = await db.select().from(settlements).where(eq(settlements.id, id));
    
    if (!settlement) return undefined;
    
    const expensesList = await db.select().from(expenses).where(eq(expenses.settlementId, id));
    const directPaymentsList = await db.select().from(directPayments).where(eq(directPayments.settlementId, id));
    
    return { ...settlement, expenses: expensesList, directPayments: directPaymentsList };
  }

  async updateSettlement(id: number, insertSettlement: any, expensesList: InsertExpense[], directPaymentsList: InsertDirectPayment[]): Promise<Settlement> {
    const [settlement] = await db.update(settlements)
      .set(insertSettlement)
      .where(eq(settlements.id, id))
      .returning();
    
    if (!settlement) throw new Error("Settlement not found");

    // Replace expenses
    await db.delete(expenses).where(eq(expenses.settlementId, id));
    if (expensesList.length > 0) {
      await db.insert(expenses).values(
        expensesList.map(e => ({ ...e, settlementId: id }))
      );
    }

    // Replace direct payments
    await db.delete(directPayments).where(eq(directPayments.settlementId, id));
    if (directPaymentsList.length > 0) {
      await db.insert(directPayments).values(
        directPaymentsList.map(dp => ({ ...dp, settlementId: id }))
      );
    }
    
    return settlement;
  }

  async deleteSettlement(id: number): Promise<void> {
    await db.delete(settlements).where(eq(settlements.id, id));
  }

  async getSettings(): Promise<AppSettingsMap> {
    const rows = await db.select().from(appSettings);
    const map: AppSettingsMap = { ...DEFAULT_SETTINGS };
    for (const row of rows) {
      map[row.key] = row.value;
    }
    return map;
  }

  async upsertSettings(settings: AppSettingsMap): Promise<AppSettingsMap> {
    const nowSecs = Math.floor(Date.now() / 1000);
    for (const [key, value] of Object.entries(settings)) {
      await db.insert(appSettings)
        .values({ key, value })
        .onConflictDoUpdate({ target: appSettings.key, set: { value, updatedAt: new Date(nowSecs * 1000) } });
    }
    return this.getSettings();
  }

  async getUsers(): Promise<User[]> {
    return await db.select().from(users).orderBy(desc(users.createdAt));
  }

  async createUser(user: InsertUser): Promise<User> {
    const [created] = await db.insert(users).values(user).returning();
    return created;
  }

  async updateUser(id: number, user: Partial<InsertUser>): Promise<User> {
    const [updated] = await db.update(users).set(user).where(eq(users.id, id)).returning();
    if (!updated) throw new Error("User not found");
    return updated;
  }

  async deleteUser(id: number): Promise<void> {
    await db.delete(users).where(eq(users.id, id));
  }
}

export const storage = new DatabaseStorage();
