import { jsonb, pgEnum, pgTable, text, timestamp } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";

export type SignatureFieldType =
  | 'client-signature'
  | 'initials'
  | 'text'
  | 'checkbox'
  | 'date'
  | 'agent-signature'
  | 'agent-initials';

export interface SignatureFieldData {
  id: string;
  page: number;   // 1-indexed
  x: number;      // PDF user space, bottom-left origin, points
  y: number;      // PDF user space, bottom-left origin, points
  width: number;  // PDF points (default: 144 — 2 inches)
  height: number; // PDF points (default: 36 — 0.5 inches)
  type?: SignatureFieldType;  // Optional — v1.0 documents have no type; fallback = 'client-signature'
  signerEmail?: string; // Optional — absent = legacy single-signer or agent-owned field
}

/**
 * Safe field type reader — always returns a SignatureFieldType, never undefined.
 * v1.0 documents have no `type` on their JSONB fields; this coalesces to 'client-signature'.
 * ALWAYS use this instead of reading field.type directly.
 */
export function getFieldType(field: SignatureFieldData): SignatureFieldType {
  return field.type ?? 'client-signature';
}

/**
 * Returns true for field types that should be visible in the client signing session.
 * agent-signature fields are embedded during document preparation and must never
 * surface to the client as required unsigned fields.
 */
export function isClientVisibleField(field: SignatureFieldData): boolean {
  const t = getFieldType(field);
  return t !== 'agent-signature' && t !== 'agent-initials';
}

/**
 * Safe signer email reader — returns the field's signerEmail or a fallback.
 * Legacy single-signer documents have no signerEmail on their fields;
 * this coalesces to the fallback (typically the document's single recipient email).
 * ALWAYS use this instead of reading field.signerEmail directly.
 */
export function getSignerEmail(field: SignatureFieldData, fallbackEmail: string): string {
  return field.signerEmail ?? fallbackEmail;
}

export const users = pgTable("users", {
  id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
  email: text("email").notNull().unique(),
  passwordHash: text("password_hash").notNull(),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  agentSignatureData: text("agent_signature_data"),
  agentInitialsData: text("agent_initials_data"),
});

export const documentStatusEnum = pgEnum("document_status", [
  "Draft",
  "Sent",
  "Viewed",
  "Signed",
]);

/**
 * A single person on a client record (primary or co-buyer).
 * Primary contact uses the top-level clients.name / clients.email.
 * Additional contacts (co-buyers, co-sellers) live in clients.contacts[].
 */
export interface ClientContact {
  name: string;
  email: string;
}

export const clients = pgTable("clients", {
  id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
  name: text("name").notNull(),
  email: text("email").notNull(),
  /** Additional contacts on this client record (co-buyers, partners, etc.) */
  contacts: jsonb("contacts").$type<ClientContact[]>(),
  propertyAddress: text("property_address"),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  updatedAt: timestamp("updated_at").defaultNow().notNull(),
});

export const formTemplates = pgTable("form_templates", {
  id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
  name: text("name").notNull(),
  filename: text("filename").notNull().unique(),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  updatedAt: timestamp("updated_at").defaultNow().notNull(),
});

/** Shape of each entry in documents.signers JSONB array. */
export interface DocumentSigner {
  email: string;
  color: string;
}

export const documents = pgTable("documents", {
  id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
  name: text("name").notNull(),
  clientId: text("client_id")
    .notNull()
    .references(() => clients.id, { onDelete: "cascade" }),
  status: documentStatusEnum("status").notNull().default("Draft"),
  sentAt: timestamp("sent_at"),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  formTemplateId: text("form_template_id").references(() => formTemplates.id),
  filePath: text("file_path"),
  signatureFields: jsonb("signature_fields").$type<SignatureFieldData[]>(),
  textFillData: jsonb("text_fill_data").$type<Record<string, string>>(),
  assignedClientId: text("assigned_client_id"),
  preparedFilePath: text("prepared_file_path"),
  /** Email addresses collected at prepare time: assigned client email + any CC addresses. */
  emailAddresses: jsonb("email_addresses").$type<string[]>(),
  signedFilePath: text("signed_file_path"),
  pdfHash: text("pdf_hash"),
  signedAt: timestamp("signed_at"),
  /** Per-signer list with assigned colors. NULL = legacy single-signer document. */
  signers: jsonb("signers").$type<DocumentSigner[]>(),
  /** Atomic completion guard — set once by the last signer's handler. NULL = not yet completed. */
  completionTriggeredAt: timestamp("completion_triggered_at"),
});

export const documentsRelations = relations(documents, ({ one }) => ({
  client: one(clients, { fields: [documents.clientId], references: [clients.id] }),
}));

export const clientsRelations = relations(clients, ({ many }) => ({
  documents: many(documents),
}));

export const auditEventTypeEnum = pgEnum('audit_event_type', [
  'document_prepared',
  'email_sent',
  'link_opened',
  'document_viewed',
  'signature_submitted',
  'pdf_hash_computed',
]);

export const signingTokens = pgTable('signing_tokens', {
  jti: text('jti').primaryKey(),
  documentId: text('document_id').notNull()
    .references(() => documents.id, { onDelete: 'cascade' }),
  /** Signer this token belongs to. NULL = legacy single-signer token. */
  signerEmail: text('signer_email'),
  createdAt: timestamp('created_at').defaultNow().notNull(),
  expiresAt: timestamp('expires_at').notNull(),
  usedAt: timestamp('used_at'),
});

export const auditEvents = pgTable('audit_events', {
  id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
  documentId: text('document_id').notNull()
    .references(() => documents.id, { onDelete: 'cascade' }),
  eventType: auditEventTypeEnum('event_type').notNull(),
  ipAddress: text('ip_address'),
  userAgent: text('user_agent'),
  metadata: jsonb('metadata').$type<Record<string, unknown>>(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
});
