import { relations } from 'drizzle-orm';
import {
  date,
  index,
  integer,
  numeric,
  pgTable,
  text,
  timestamp,
  uniqueIndex,
  uuid,
  varchar,
} from 'drizzle-orm/pg-core';
import { users } from './auth';
import {
  tradeDirectionEnum,
  tradeResultEnum,
  tradeTypeEnum,
  tradingCashTransactionTypeEnum,
} from './enums';

const financial = (name: string) => numeric(name, { precision: 38, scale: 18 });

export const tradingAccounts = pgTable(
  'trading_accounts',
  {
    id: uuid('id').defaultRandom().primaryKey(),
    ownerId: uuid('owner_id')
      .notNull()
      .references(() => users.id, { onDelete: 'cascade' }),
    name: varchar('name', { length: 120 }).notNull(),
    color: varchar('color', { length: 24 }),
    exchange: varchar('exchange', { length: 80 }),
    description: text('description'),
    version: integer('version').notNull().default(1),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [
    index('trading_accounts_owner_id_idx').on(table.ownerId),
    uniqueIndex('trading_accounts_owner_name_unique').on(table.ownerId, table.name),
  ],
);

export const trades = pgTable(
  'trades',
  {
    id: uuid('id').defaultRandom().primaryKey(),
    accountId: uuid('account_id')
      .notNull()
      .references(() => tradingAccounts.id, { onDelete: 'cascade' }),
    openDate: date('open_date', { mode: 'string' }).notNull(),
    closeDate: date('close_date', { mode: 'string' }),
    asset: varchar('asset', { length: 30 }).notNull(),
    direction: tradeDirectionEnum('direction').notNull(),
    tradeType: tradeTypeEnum('trade_type').notNull(),
    result: tradeResultEnum('result').notNull(),
    entry: financial('entry'),
    exit: financial('exit'),
    stopLoss: financial('stop_loss'),
    takeProfit: financial('take_profit'),
    liquidationPrice: financial('liquidation_price'),
    leverage: financial('leverage'),
    capital: financial('capital'),
    quantity: financial('quantity'),
    baseQuantity: financial('base_quantity'),
    baseEntry: financial('base_entry'),
    baseCapital: financial('base_capital'),
    pnl: financial('pnl'),
    setup: text('setup'),
    emotion: text('emotion'),
    notes: text('notes'),
    version: integer('version').notNull().default(1),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [
    index('trades_account_id_idx').on(table.accountId),
    index('trades_account_open_date_idx').on(table.accountId, table.openDate),
    index('trades_account_result_idx').on(table.accountId, table.result),
    index('trades_asset_idx').on(table.asset),
  ],
);

export const tradeAdditions = pgTable(
  'trade_additions',
  {
    id: uuid('id').defaultRandom().primaryKey(),
    tradeId: uuid('trade_id')
      .notNull()
      .references(() => trades.id, { onDelete: 'cascade' }),
    date: date('date', { mode: 'string' }).notNull(),
    quantity: financial('quantity'),
    price: financial('price'),
    margin: financial('margin'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [index('trade_additions_trade_id_idx').on(table.tradeId, table.date)],
);

export const tradePartials = pgTable(
  'trade_partials',
  {
    id: uuid('id').defaultRandom().primaryKey(),
    tradeId: uuid('trade_id')
      .notNull()
      .references(() => trades.id, { onDelete: 'cascade' }),
    date: date('date', { mode: 'string' }).notNull(),
    quantity: financial('quantity'),
    price: financial('price'),
    pnl: financial('pnl'),
    note: text('note'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [index('trade_partials_trade_id_idx').on(table.tradeId, table.date)],
);

export const tradingCashTransactions = pgTable(
  'trading_cash_transactions',
  {
    id: uuid('id').defaultRandom().primaryKey(),
    accountId: uuid('account_id')
      .notNull()
      .references(() => tradingAccounts.id, { onDelete: 'cascade' }),
    date: date('date', { mode: 'string' }).notNull(),
    type: tradingCashTransactionTypeEnum('type').notNull(),
    amount: financial('amount').notNull(),
    currency: varchar('currency', { length: 12 }).notNull(),
    toCurrency: varchar('to_currency', { length: 12 }),
    toAmount: financial('to_amount'),
    counterparty: varchar('counterparty', { length: 160 }),
    note: text('note'),
    version: integer('version').notNull().default(1),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [index('trading_cash_transactions_account_id_idx').on(table.accountId, table.date)],
);

export const tradingAccountsRelations = relations(tradingAccounts, ({ one, many }) => ({
  owner: one(users, {
    fields: [tradingAccounts.ownerId],
    references: [users.id],
  }),
  trades: many(trades),
  cashTransactions: many(tradingCashTransactions),
}));

export const tradesRelations = relations(trades, ({ one, many }) => ({
  account: one(tradingAccounts, {
    fields: [trades.accountId],
    references: [tradingAccounts.id],
  }),
  additions: many(tradeAdditions),
  partials: many(tradePartials),
}));

export const tradeAdditionsRelations = relations(tradeAdditions, ({ one }) => ({
  trade: one(trades, {
    fields: [tradeAdditions.tradeId],
    references: [trades.id],
  }),
}));

export const tradePartialsRelations = relations(tradePartials, ({ one }) => ({
  trade: one(trades, {
    fields: [tradePartials.tradeId],
    references: [trades.id],
  }),
}));

export type TradingAccount = typeof tradingAccounts.$inferSelect;
export type Trade = typeof trades.$inferSelect;
