import {
  boolean,
  index,
  integer,
  jsonb,
  pgEnum,
  pgTable,
  text,
  timestamp,
  uniqueIndex,
  uuid,
} from "drizzle-orm/pg-core";
import { sql } from "drizzle-orm";

export const instanceStatus = pgEnum("instance_status", ["active", "blocked", "disabled"]);
export const payloadMode = pgEnum("payload_mode", ["minimal", "rich"]);
export const devicePlatform = pgEnum("device_platform", ["web", "ios", "android"]);
export const deviceStatus = pgEnum("device_status", ["active", "disabled", "invalid"]);
export const deliveryStatus = pgEnum("delivery_status", ["accepted", "processing", "completed", "failed", "partial"]);
export const attemptStatus = pgEnum("attempt_status", ["pending", "sent", "failed", "skipped"]);
export const attemptProvider = pgEnum("attempt_provider", ["web_push", "apns", "fcm"]);

export const pushInstances = pgTable(
  "push_instances",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    instanceId: text("instance_id").notNull().unique(),
    name: text("name").notNull(),
    baseUrl: text("base_url").notNull(),
    status: instanceStatus("status").notNull().default("active"),
    mode: payloadMode("payload_mode").notNull().default("minimal"),
    capabilities: jsonb("capabilities").$type<string[]>().notNull().default(sql`'[]'::jsonb`),
    rateLimitPerMinute: integer("rate_limit_per_minute").notNull().default(120),
    dailyQuota: integer("daily_quota").notNull().default(10000),
    currentSecretEncrypted: text("current_secret_encrypted").notNull(),
    currentSecretPreview: text("current_secret_preview").notNull(),
    nextSecretEncrypted: text("next_secret_encrypted"),
    nextSecretPreview: text("next_secret_preview"),
    notes: text("notes"),
    lastHeartbeatAt: timestamp("last_heartbeat_at", { withTimezone: true }),
    lastHeartbeatVersion: text("last_heartbeat_version"),
    lastHeartbeatIp: text("last_heartbeat_ip"),
    createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => ({
    instanceIdIdx: uniqueIndex("push_instances_instance_id_idx").on(table.instanceId),
    statusIdx: index("push_instances_status_idx").on(table.status),
  }),
);

export const pushDevices = pgTable(
  "push_devices",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    centralDeviceId: text("central_device_id").notNull().unique(),
    instanceId: uuid("instance_id")
      .notNull()
      .references(() => pushInstances.id, { onDelete: "cascade" }),
    localDeviceId: text("local_device_id").notNull(),
    platform: devicePlatform("platform").notNull(),
    status: deviceStatus("status").notNull().default("active"),
    providerTokenEncrypted: text("provider_token_encrypted"),
    webPushSubscription: jsonb("web_push_subscription").$type<Record<string, unknown>>(),
    meta: jsonb("meta").$type<Record<string, unknown>>().notNull().default(sql`'{}'::jsonb`),
    lastSeenAt: timestamp("last_seen_at", { withTimezone: true }).notNull().defaultNow(),
    disabledAt: timestamp("disabled_at", { withTimezone: true }),
    createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => ({
    centralDeviceIdIdx: uniqueIndex("push_devices_central_device_id_idx").on(table.centralDeviceId),
    instanceLocalDeviceIdx: uniqueIndex("push_devices_instance_local_device_idx").on(table.instanceId, table.localDeviceId),
    instanceStatusIdx: index("push_devices_instance_status_idx").on(table.instanceId, table.status),
  }),
);

export const deliveryJobs = pgTable(
  "delivery_jobs",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    deliveryJobId: text("delivery_job_id").notNull().unique(),
    instanceId: uuid("instance_id")
      .notNull()
      .references(() => pushInstances.id, { onDelete: "cascade" }),
    idempotencyKey: text("idempotency_key").notNull(),
    status: deliveryStatus("status").notNull().default("accepted"),
    priority: text("priority").notNull().default("normal"),
    collapseKey: text("collapse_key"),
    ttlSeconds: integer("ttl_seconds").notNull().default(3600),
    acceptedCount: integer("accepted_count").notNull().default(0),
    rejectedCount: integer("rejected_count").notNull().default(0),
    sentCount: integer("sent_count").notNull().default(0),
    failedCount: integer("failed_count").notNull().default(0),
    lastErrorCode: text("last_error_code"),
    lastErrorMessage: text("last_error_message"),
    completedAt: timestamp("completed_at", { withTimezone: true }),
    createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => ({
    deliveryJobIdIdx: uniqueIndex("delivery_jobs_delivery_job_id_idx").on(table.deliveryJobId),
    instanceIdempotencyIdx: uniqueIndex("delivery_jobs_instance_idempotency_idx").on(table.instanceId, table.idempotencyKey),
    instanceCreatedIdx: index("delivery_jobs_instance_created_idx").on(table.instanceId, table.createdAt),
  }),
);

export const deliveryAttempts = pgTable(
  "delivery_attempts",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    deliveryJobId: uuid("delivery_job_id")
      .notNull()
      .references(() => deliveryJobs.id, { onDelete: "cascade" }),
    deviceId: uuid("device_id")
      .notNull()
      .references(() => pushDevices.id, { onDelete: "cascade" }),
    provider: attemptProvider("provider").notNull(),
    status: attemptStatus("status").notNull().default("pending"),
    providerMessageId: text("provider_message_id"),
    errorCode: text("error_code"),
    errorMessage: text("error_message"),
    sentAt: timestamp("sent_at", { withTimezone: true }),
    createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => ({
    jobIdx: index("delivery_attempts_job_idx").on(table.deliveryJobId),
    deviceIdx: index("delivery_attempts_device_idx").on(table.deviceId),
  }),
);

export const auditLogs = pgTable(
  "audit_logs",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    actor: text("actor").notNull(),
    action: text("action").notNull(),
    instanceId: uuid("instance_id").references(() => pushInstances.id, { onDelete: "set null" }),
    meta: jsonb("meta").$type<Record<string, unknown>>().notNull().default(sql`'{}'::jsonb`),
    createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => ({
    instanceCreatedIdx: index("audit_logs_instance_created_idx").on(table.instanceId, table.createdAt),
  }),
);

export type PushInstance = typeof pushInstances.$inferSelect;
export type NewPushInstance = typeof pushInstances.$inferInsert;
export type PushDevice = typeof pushDevices.$inferSelect;
export type NewPushDevice = typeof pushDevices.$inferInsert;
export type DeliveryJob = typeof deliveryJobs.$inferSelect;
export type NewDeliveryJob = typeof deliveryJobs.$inferInsert;
export type DeliveryAttempt = typeof deliveryAttempts.$inferSelect;
export type NewDeliveryAttempt = typeof deliveryAttempts.$inferInsert;
