import { relations } from "drizzle-orm";
import {
  boolean,
  date,
  index,
  integer,
  jsonb,
  numeric,
  pgEnum,
  pgTable,
  text,
  timestamp,
  uniqueIndex,
} from "drizzle-orm/pg-core";
import { user } from "./auth";

// Enums
export const subscriptionPlanEnum = pgEnum("subscription_plan", ["free", "pro", "family"]);
export const subscriptionStatusEnum = pgEnum("subscription_status", ["active", "canceled", "past_due"]);
export const categoryTypeEnum = pgEnum("category_type", ["income", "expense"]);
export const transactionTypeEnum = pgEnum("transaction_type", ["income", "expense"]);
export const transactionScopeEnum = pgEnum("transaction_scope", ["household", "private", "child"]);
export const syncOperationEnum = pgEnum("sync_operation", ["create", "update", "delete"]);

// households table (tenant)
export const households = pgTable("households", {
  id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
  name: text("name").notNull(),
  ownerId: text("owner_id").notNull().references(() => user.id, { onDelete: "cascade" }),
  createdAt: timestamp("created_at").defaultNow().notNull(),
});

// subscription_plans table
export const subscriptionPlans = pgTable(
  "subscription_plans",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    plan: subscriptionPlanEnum("plan").notNull().default("free"),
    status: subscriptionStatusEnum("status").notNull().default("active"),
    stripeCustomerId: text("stripe_customer_id"),
    stripeSubscriptionId: text("stripe_subscription_id"),
    currentPeriodStart: timestamp("current_period_start"),
    currentPeriodEnd: timestamp("current_period_end"),
    createdAt: timestamp("created_at").defaultNow().notNull(),
    updatedAt: timestamp("updated_at").defaultNow().$onUpdate(() => new Date()).notNull(),
  },
  (table) => [index("subscription_plans_household_id_idx").on(table.householdId)],
);

// categories table
export const categories = pgTable(
  "categories",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    name: text("name").notNull(),
    icon: text("icon"),
    color: text("color"),
    type: categoryTypeEnum("type").notNull(),
    isDefault: boolean("is_default").notNull().default(false),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [index("categories_household_id_idx").on(table.householdId)],
);

// children table
export const children = pgTable(
  "children",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    name: text("name").notNull(),
    color: text("color").notNull().default("#378ADD"),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [index("children_household_id_idx").on(table.householdId)],
);

// transactions table
export const transactions = pgTable(
  "transactions",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
    categoryId: text("category_id").references(() => categories.id, { onDelete: "set null" }),
    childId: text("child_id").references(() => children.id, { onDelete: "set null" }),
    scope: transactionScopeEnum("scope").notNull().default("household"),
    amount: numeric("amount", { precision: 12, scale: 2 }).notNull(),
    currency: text("currency").notNull().default("EUR"),
    type: transactionTypeEnum("type").notNull(),
    isFixed: boolean("is_fixed").notNull().default(false),
    isCarryOver: boolean("is_carry_over").notNull().default(false),
    description: text("description"),
    merchant: text("merchant"),
    date: date("date").notNull(),
    receiptImageUrl: text("receipt_image_url"),
    syncedAt: timestamp("synced_at"),
    createdAt: timestamp("created_at").defaultNow().notNull(),
    updatedAt: timestamp("updated_at").defaultNow().$onUpdate(() => new Date()).notNull(),
  },
  (table) => [
    index("transactions_household_id_idx").on(table.householdId),
    index("transactions_user_id_idx").on(table.userId),
    index("transactions_date_idx").on(table.date),
    index("transactions_scope_idx").on(table.scope),
  ],
);

// vacations table (replaces budget_contexts)
export const vacations = pgTable(
  "vacations",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    name: text("name").notNull(),
    budget: numeric("budget", { precision: 12, scale: 2 }),
    currency: text("currency").notNull().default("EUR"),
    startsOn: date("starts_on"),
    endsOn: date("ends_on"),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [index("vacations_household_id_idx").on(table.householdId)],
);

// vacation_entries table
export const vacationEntries = pgTable(
  "vacation_entries",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    vacationId: text("vacation_id").notNull().references(() => vacations.id, { onDelete: "cascade" }),
    createdBy: text("created_by").notNull().references(() => user.id, { onDelete: "cascade" }),
    categoryId: text("category_id").references(() => categories.id, { onDelete: "set null" }),
    amount: numeric("amount", { precision: 12, scale: 2 }).notNull(),
    currency: text("currency").notNull().default("EUR"),
    description: text("description"),
    date: date("date").notNull(),
    syncedAt: timestamp("synced_at"),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [index("vacation_entries_vacation_id_idx").on(table.vacationId)],
);

// shopping_lists table
export const shoppingLists = pgTable(
  "shopping_lists",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    name: text("name").notNull(),
    isActive: boolean("is_active").notNull().default(true),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [index("shopping_lists_household_id_idx").on(table.householdId)],
);

// shopping_list_items table
export const shoppingListItems = pgTable(
  "shopping_list_items",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    listId: text("list_id").notNull().references(() => shoppingLists.id, { onDelete: "cascade" }),
    addedByUserId: text("added_by_user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
    name: text("name").notNull(),
    quantity: numeric("quantity", { precision: 10, scale: 2 }),
    unit: text("unit"),
    isChecked: boolean("is_checked").notNull().default(false),
    checkedByUserId: text("checked_by_user_id").references(() => user.id, { onDelete: "set null" }),
    checkedAt: timestamp("checked_at"),
    createdAt: timestamp("created_at").defaultNow().notNull(),
    updatedAt: timestamp("updated_at").defaultNow().$onUpdate(() => new Date()).notNull(),
  },
  (table) => [index("shopping_list_items_list_id_idx").on(table.listId)],
);

// shopping_items table — flat, household-scoped real-time shopping list
export const shoppingItems = pgTable(
  "shopping_items",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    label: text("label").notNull(),
    quantity: text("quantity"),
    addedBy: text("added_by").notNull(),
    checkedBy: text("checked_by"),
    checkedAt: text("checked_at"),
    sortOrder: integer("sort_order").notNull().default(0),
    createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
  },
  (table) => [index("shopping_items_household_id_idx").on(table.householdId)],
);

// savings_goals table
export const savingsGoals = pgTable(
  "savings_goals",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    name: text("name").notNull(),
    targetAmount: numeric("target_amount", { precision: 12, scale: 2 }).notNull(),
    currentAmount: numeric("current_amount", { precision: 12, scale: 2 }).notNull().default("0"),
    targetDate: date("target_date"),
    allocationPercent: numeric("allocation_percent", { precision: 5, scale: 2 }),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [index("savings_goals_household_id_idx").on(table.householdId)],
);

// fixed_costs table — recurring transaction templates
export const fixedCosts = pgTable(
  "fixed_costs",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    scope: transactionScopeEnum("scope").notNull().default("household"),
    childId: text("child_id").references(() => children.id, { onDelete: "set null" }),
    categoryId: text("category_id").references(() => categories.id, { onDelete: "set null" }),
    label: text("label").notNull(),
    amount: numeric("amount", { precision: 12, scale: 2 }).notNull(),
    type: transactionTypeEnum("type").notNull().default("expense"),
    isActive: boolean("is_active").notNull().default(true),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [
    index("fixed_costs_household_id_idx").on(table.householdId),
    index("fixed_costs_scope_idx").on(table.scope),
  ],
);

// monthly_transfers table — recorded money transfers between members
export const monthlyTransfers = pgTable(
  "monthly_transfers",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    month: text("month").notNull(), // "YYYY-MM"
    fromUserId: text("from_user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
    toUserId: text("to_user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
    amount: numeric("amount", { precision: 12, scale: 2 }).notNull(),
    note: text("note"),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [
    index("monthly_transfers_household_id_idx").on(table.householdId),
    index("monthly_transfers_month_idx").on(table.month),
  ],
);

// transfer_line_items table — fixed additions to settlement calculation
export const transferLineItems = pgTable(
  "transfer_line_items",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    label: text("label").notNull(),
    amount: numeric("amount", { precision: 12, scale: 2 }).notNull(),
    isActive: boolean("is_active").notNull().default(true),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [index("transfer_line_items_household_id_idx").on(table.householdId)],
);

// month_status table
export const monthStatus = pgTable(
  "month_status",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    month: text("month").notNull(), // 'YYYY-MM'
    status: text("status", { enum: ["open", "closed"] }).notNull().default("open"),
    closedAt: timestamp("closed_at"),
    closedBy: text("closed_by").references(() => user.id, { onDelete: "set null" }),
    finalAmount: numeric("final_amount", { precision: 12, scale: 2 }),
    notes: text("notes"),
    finalTransferId: text("final_transfer_id"), // references monthly_transfers.id (no FK to avoid circular)
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [
    index("month_status_household_id_idx").on(table.householdId),
    index("month_status_month_idx").on(table.month),
    uniqueIndex("month_status_household_month_unique").on(table.householdId, table.month),
  ],
);

// household_settings table
export const householdSettings = pgTable("household_settings", {
  id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
  householdId: text("household_id").notNull().unique().references(() => households.id, { onDelete: "cascade" }),
  ownerName: text("owner_name").notNull().default("Ich"),
  partnerName: text("partner_name").notNull().default("Partner"),
  userSharePercent: numeric("user_share_percent", { precision: 5, scale: 2 }).notNull().default("50"),
  monthlyBudget: numeric("monthly_budget", { precision: 12, scale: 2 }).notNull().default("400"),
  currency: text("currency").notNull().default("EUR"),
  splitChildCosts: boolean("split_child_costs").notNull().default(true),
  payerUserId: text("payer_user_id"),
  onboardingComplete: boolean("onboarding_complete").notNull().default(false),
  language: text("language").notNull().default("auto"),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  updatedAt: timestamp("updated_at").defaultNow().$onUpdate(() => new Date()).notNull(),
});

// debts table
export const debts = pgTable(
  "debts",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
    creditorUserId: text("creditor_user_id").references(() => user.id, { onDelete: "set null" }),
    label: text("label").notNull(),
    creditor: text("creditor"),
    totalAmount: numeric("total_amount", { precision: 12, scale: 2 }).notNull(),
    notes: text("notes"),
    createdAt: timestamp("created_at").defaultNow().notNull(),
    closedAt: timestamp("closed_at"),
  },
  (table) => [
    index("debts_household_id_idx").on(table.householdId),
    index("debts_user_id_idx").on(table.userId),
  ],
);

// debt_payments table
export const debtPayments = pgTable(
  "debt_payments",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    debtId: text("debt_id").notNull().references(() => debts.id, { onDelete: "cascade" }),
    amount: numeric("amount", { precision: 12, scale: 2 }).notNull(),
    date: date("date").notNull(),
    note: text("note"),
    linkedTransactionId: text("linked_transaction_id").references(() => transactions.id, { onDelete: "set null" }),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [index("debt_payments_debt_id_idx").on(table.debtId)],
);

// sync_queue table (Phase 2 — offline support)
export const syncQueue = pgTable(
  "sync_queue",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
    operation: syncOperationEnum("operation").notNull(),
    tableName: text("table_name").notNull(),
    payload: jsonb("payload").notNull(),
    attempts: numeric("attempts").notNull().default("0"),
    lastError: text("last_error"),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [index("sync_queue_household_id_idx").on(table.householdId)],
);

// trips table
export const trips = pgTable(
  "trips",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    householdId: text("household_id").notNull().references(() => households.id, { onDelete: "cascade" }),
    name: text("name").notNull(),
    destination: text("destination"),
    budget: numeric("budget", { precision: 12, scale: 2 }).notNull(),
    startDate: text("start_date").notNull(),
    endDate: text("end_date").notNull(),
    status: text("status").notNull().default("active"),
    settlementFromUserId: text("settlement_from_user_id"),
    settlementToUserId: text("settlement_to_user_id"),
    settlementAmount: numeric("settlement_amount", { precision: 12, scale: 2 }),
    settledAt: text("settled_at"),
    createdAt: timestamp("created_at").defaultNow().notNull(),
    updatedAt: timestamp("updated_at").defaultNow().$onUpdate(() => new Date()).notNull(),
  },
  (table) => [index("trips_household_id_idx").on(table.householdId)],
);

// trip_expenses table
export const tripExpenses = pgTable(
  "trip_expenses",
  {
    id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
    tripId: text("trip_id").notNull().references(() => trips.id, { onDelete: "cascade" }),
    householdId: text("household_id").notNull(),
    label: text("label").notNull(),
    amount: numeric("amount", { precision: 12, scale: 2 }).notNull(),
    category: text("category").notNull().default("sonstiges"),
    paidBy: text("paid_by").notNull(),
    date: text("date").notNull(),
    note: text("note"),
    createdAt: timestamp("created_at").defaultNow().notNull(),
  },
  (table) => [
    index("trip_expenses_trip_id_idx").on(table.tripId),
    index("trip_expenses_household_id_idx").on(table.householdId),
  ],
);

// household_invitations table — short-lived join codes
export const householdInvitations = pgTable("household_invitations", {
  id: text("id").primaryKey(),
  householdId: text("household_id").notNull(),
  code: text("code").notNull().unique(),
  createdBy: text("created_by").notNull(),
  expiresAt: text("expires_at").notNull(),
  usedAt: text("used_at"),
  usedBy: text("used_by"),
  createdAt: text("created_at").notNull(),
});

// Relations
export const householdsRelations = relations(households, ({ one, many }) => ({
  owner: one(user, { fields: [households.ownerId], references: [user.id] }),
  subscriptionPlan: one(subscriptionPlans, { fields: [households.id], references: [subscriptionPlans.householdId] }),
  categories: many(categories),
  children: many(children),
  transactions: many(transactions),
  vacations: many(vacations),
  shoppingLists: many(shoppingLists),
  savingsGoals: many(savingsGoals),
  debts: many(debts),
  fixedCosts: many(fixedCosts),
  settings: one(householdSettings, { fields: [households.id], references: [householdSettings.householdId] }),
  monthlyTransfers: many(monthlyTransfers),
  transferLineItems: many(transferLineItems),
  trips: many(trips),
}));

export const subscriptionPlansRelations = relations(subscriptionPlans, ({ one }) => ({
  household: one(households, { fields: [subscriptionPlans.householdId], references: [households.id] }),
}));

export const householdSettingsRelations = relations(householdSettings, ({ one }) => ({
  household: one(households, { fields: [householdSettings.householdId], references: [households.id] }),
}));

export const monthStatusRelations = relations(monthStatus, ({ one }) => ({
  household: one(households, { fields: [monthStatus.householdId], references: [households.id] }),
  closedByUser: one(user, { fields: [monthStatus.closedBy], references: [user.id] }),
}));

export const categoriesRelations = relations(categories, ({ one, many }) => ({
  household: one(households, { fields: [categories.householdId], references: [households.id] }),
  transactions: many(transactions),
  vacationEntries: many(vacationEntries),
}));

export const childrenRelations = relations(children, ({ one, many }) => ({
  household: one(households, { fields: [children.householdId], references: [households.id] }),
  transactions: many(transactions),
}));

export const transactionsRelations = relations(transactions, ({ one }) => ({
  household: one(households, { fields: [transactions.householdId], references: [households.id] }),
  user: one(user, { fields: [transactions.userId], references: [user.id] }),
  category: one(categories, { fields: [transactions.categoryId], references: [categories.id] }),
  child: one(children, { fields: [transactions.childId], references: [children.id] }),
}));

export const vacationsRelations = relations(vacations, ({ one, many }) => ({
  household: one(households, { fields: [vacations.householdId], references: [households.id] }),
  entries: many(vacationEntries),
}));

export const vacationEntriesRelations = relations(vacationEntries, ({ one }) => ({
  vacation: one(vacations, { fields: [vacationEntries.vacationId], references: [vacations.id] }),
  createdByUser: one(user, { fields: [vacationEntries.createdBy], references: [user.id] }),
  category: one(categories, { fields: [vacationEntries.categoryId], references: [categories.id] }),
}));

export const shoppingListsRelations = relations(shoppingLists, ({ one, many }) => ({
  household: one(households, { fields: [shoppingLists.householdId], references: [households.id] }),
  items: many(shoppingListItems),
}));

export const shoppingListItemsRelations = relations(shoppingListItems, ({ one }) => ({
  list: one(shoppingLists, { fields: [shoppingListItems.listId], references: [shoppingLists.id] }),
  addedByUser: one(user, { fields: [shoppingListItems.addedByUserId], references: [user.id] }),
  checkedByUser: one(user, { fields: [shoppingListItems.checkedByUserId], references: [user.id] }),
}));

export const savingsGoalsRelations = relations(savingsGoals, ({ one }) => ({
  household: one(households, { fields: [savingsGoals.householdId], references: [households.id] }),
}));

export const shoppingItemsRelations = relations(shoppingItems, ({ one }) => ({
  household: one(households, { fields: [shoppingItems.householdId], references: [households.id] }),
}));

export const fixedCostsRelations = relations(fixedCosts, ({ one }) => ({
  household: one(households, { fields: [fixedCosts.householdId], references: [households.id] }),
  category: one(categories, { fields: [fixedCosts.categoryId], references: [categories.id] }),
  child: one(children, { fields: [fixedCosts.childId], references: [children.id] }),
}));

export const monthlyTransfersRelations = relations(monthlyTransfers, ({ one }) => ({
  household: one(households, { fields: [monthlyTransfers.householdId], references: [households.id] }),
  fromUser: one(user, { fields: [monthlyTransfers.fromUserId], references: [user.id] }),
  toUser: one(user, { fields: [monthlyTransfers.toUserId], references: [user.id] }),
}));

export const transferLineItemsRelations = relations(transferLineItems, ({ one }) => ({
  household: one(households, { fields: [transferLineItems.householdId], references: [households.id] }),
}));

export const debtsRelations = relations(debts, ({ one, many }) => ({
  household: one(households, { fields: [debts.householdId], references: [households.id] }),
  user: one(user, { fields: [debts.userId], references: [user.id] }),
  payments: many(debtPayments),
}));

export const debtPaymentsRelations = relations(debtPayments, ({ one }) => ({
  debt: one(debts, { fields: [debtPayments.debtId], references: [debts.id] }),
  linkedTransaction: one(transactions, { fields: [debtPayments.linkedTransactionId], references: [transactions.id] }),
}));

export const syncQueueRelations = relations(syncQueue, ({ one }) => ({
  household: one(households, { fields: [syncQueue.householdId], references: [households.id] }),
  user: one(user, { fields: [syncQueue.userId], references: [user.id] }),
}));

export const tripsRelations = relations(trips, ({ one, many }) => ({
  household: one(households, { fields: [trips.householdId], references: [households.id] }),
  expenses: many(tripExpenses),
}));

export const tripExpensesRelations = relations(tripExpenses, ({ one }) => ({
  trip: one(trips, { fields: [tripExpenses.tripId], references: [trips.id] }),
}));
