import dotenv from "dotenv";
import { roleDefinitions, permissions } from "./rbac";
import { hashCredentialPassword } from "./auth-utils";

dotenv.config({
  path: new URL("../../../apps/server/.env", import.meta.url).pathname,
});

import { db } from "./index";
import { account, permission, role, rolePermission, user, userRole } from "./schema/auth";
import { domain, note, server, service } from "./schema/monitoring";

const now = new Date();
const earlierToday = new Date(now.getTime() - 45 * 60 * 1000);
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);

const adminUser = {
  id: "user_admin_minmon",
  name: "Minmon Admin",
  email: "admin@minmon.local",
  password: "admin12345",
};

const servers = [
  {
    id: "server_prod_1",
    name: "Production VPS",
    primaryIpAddress: "203.0.113.10",
    secondaryIpAddress: "203.0.113.11",
    operatingSystem: "Ubuntu 24.04 LTS",
    location: "Singapore",
    provider: "DigitalOcean",
    description: "Main production server hosting the dashboard web app, API, and reverse proxy.",
    status: "active" as const,
  },
  {
    id: "server_mail_1",
    name: "Mail Server",
    primaryIpAddress: "198.51.100.20",
    secondaryIpAddress: null,
    operatingSystem: "Debian 12",
    location: "Jakarta",
    provider: "Hetzner",
    description: "Handles the demo mail service and SMTP/IMAP examples.",
    status: "maintenance" as const,
  },
  {
    id: "server_lab_1",
    name: "Campus Lab VM",
    primaryIpAddress: "192.0.2.18",
    secondaryIpAddress: null,
    operatingSystem: "Ubuntu 22.04 LTS",
    location: "Campus Lab",
    provider: "University Lab",
    description: "Used for student practice and lecturer demonstration in class.",
    status: "inactive" as const,
  },
];

const services = [
  {
    id: "service_dashboard_web",
    serverId: "server_prod_1",
    name: "Dashboard Web",
    type: "web_app" as const,
    internalPort: 3000,
    externalPort: 443,
    protocol: "https" as const,
    status: "active" as const,
    description: "Frontend application for the private server management dashboard.",
  },
  {
    id: "service_dashboard_api",
    serverId: "server_prod_1",
    name: "Dashboard API",
    type: "api" as const,
    internalPort: 3001,
    externalPort: 443,
    protocol: "https" as const,
    status: "active" as const,
    description: "Handles CRUD data, dashboard summary, and DNS checks.",
  },
  {
    id: "service_mail_gateway",
    serverId: "server_mail_1",
    name: "Mail Gateway",
    type: "mail" as const,
    internalPort: 25,
    externalPort: 25,
    protocol: "tcp" as const,
    status: "maintenance" as const,
    description: "Mail service used as a sample SMTP gateway for the assignment.",
  },
  {
    id: "service_lab_proxy",
    serverId: "server_lab_1",
    name: "Lab Reverse Proxy",
    type: "proxy" as const,
    internalPort: 80,
    externalPort: 80,
    protocol: "http" as const,
    status: "down" as const,
    description: "Reverse proxy for local practice deployments in the campus lab.",
  },
];

const domains = [
  {
    id: "domain_dashboard_web",
    serviceId: "service_dashboard_web",
    name: "dashboard.minmon.dev",
    expectedServerIp: "203.0.113.10",
    lastResolvedIp: "203.0.113.10",
    lastResolvedIps: ["203.0.113.10"],
    resolutionStatus: "MATCH" as const,
    lastCheckedAt: earlierToday,
    remarks: "Primary domain for the dashboard frontend.",
    lastCheckMessage: null,
  },
  {
    id: "domain_dashboard_api",
    serviceId: "service_dashboard_api",
    name: "api.minmon.dev",
    expectedServerIp: "203.0.113.10",
    lastResolvedIp: "203.0.113.15",
    lastResolvedIps: ["203.0.113.15", "203.0.113.10"],
    resolutionStatus: "MATCH" as const,
    lastCheckedAt: earlierToday,
    remarks: "API subdomain. Multiple A records still include the expected IP.",
    lastCheckMessage: null,
  },
  {
    id: "domain_mail_gateway",
    serviceId: "service_mail_gateway",
    name: "mail.minmon.dev",
    expectedServerIp: "198.51.100.20",
    lastResolvedIp: "198.51.100.77",
    lastResolvedIps: ["198.51.100.77"],
    resolutionStatus: "MISMATCH" as const,
    lastCheckedAt: yesterday,
    remarks: "DNS still points to the old mail gateway.",
    lastCheckMessage: null,
  },
  {
    id: "domain_lab_demo",
    serviceId: "service_lab_proxy",
    name: "lab.minmon.dev",
    expectedServerIp: "192.0.2.18",
    lastResolvedIp: null,
    lastResolvedIps: [],
    resolutionStatus: "UNRESOLVED" as const,
    lastCheckedAt: yesterday,
    remarks: "Lab VM is powered off outside teaching hours.",
    lastCheckMessage: "DNS lookup failed because the host could not be resolved.",
  },
];

const notes = [
  {
    id: "note_prod_backup",
    serverId: "server_prod_1",
    title: "Weekly backup reminder",
    content: "Verify the PostgreSQL backup every Friday before the lecturer demo session.",
    category: "maintenance",
  },
  {
    id: "note_prod_dataset",
    serverId: "server_prod_1",
    title: "Main sample dataset",
    content:
      "This production server and its services form the main student-facing sample dataset for CRUD and monitoring demos.",
    category: "general",
  },
  {
    id: "note_mail_dns",
    serverId: "server_mail_1",
    title: "Update stale A record",
    content: "Point mail.minmon.dev to the current mail server before final presentation week.",
    category: "todo",
  },
  {
    id: "note_lab_status",
    serverId: "server_lab_1",
    title: "Lab VM inactive",
    content: "The campus lab VM is intentionally inactive outside class hours, so related checks may fail.",
    category: "incident",
  },
];

async function seedAuthAdmin() {
  const existingUser = await db.query.user.findFirst({
    where: (table, { eq }) => eq(table.email, adminUser.email),
  });

  if (existingUser) {
    return existingUser.id;
  }

  const passwordHash = await hashCredentialPassword(adminUser.password);

  await db.insert(user).values({
    id: adminUser.id,
    name: adminUser.name,
    email: adminUser.email,
    emailVerified: true,
    createdAt: now,
    updatedAt: now,
  });

  await db.insert(account).values({
    id: "account_admin_minmon",
    accountId: adminUser.id,
    providerId: "credential",
    userId: adminUser.id,
    password: passwordHash,
    createdAt: now,
    updatedAt: now,
  });

  return adminUser.id;
}

export async function seedRolesAndPermissions(adminUserId?: string) {
  await db.insert(permission).values(
    permissions.map((name) => ({
      id: name,
      name,
      description: `Allows ${name.replace(".", " ")}`,
      createdAt: now,
      updatedAt: now,
    })),
  ).onConflictDoNothing();

  await db.insert(role).values(
    roleDefinitions.map((item) => ({
      id: item.id,
      name: item.name,
      description: item.description,
      createdAt: now,
      updatedAt: now,
    })),
  ).onConflictDoNothing();

  await db.insert(rolePermission).values(
    roleDefinitions.flatMap((item) =>
      item.permissions.map((permissionName) => ({
        roleId: item.id,
        permissionId: permissionName,
        createdAt: now,
      })),
    ),
  ).onConflictDoNothing();

  if (adminUserId) {
    await db.insert(userRole).values({
      userId: adminUserId,
      roleId: "role_admin",
      createdAt: now,
    }).onConflictDoNothing();
  }
}

async function seedMonitoringData() {
  await db.delete(note);
  await db.delete(domain);
  await db.delete(service);
  await db.delete(server);

  await db.insert(server).values(
    servers.map((item) => ({
      ...item,
      secondaryIpAddress: item.secondaryIpAddress ?? undefined,
      createdAt: now,
      updatedAt: now,
    })),
  );

  await db.insert(service).values(
    services.map((item) => ({
      ...item,
      createdAt: now,
      updatedAt: now,
    })),
  );

  await db.insert(domain).values(
    domains.map((item) => ({
      ...item,
      lastResolvedIp: item.lastResolvedIp ?? undefined,
      lastCheckMessage: item.lastCheckMessage ?? undefined,
      createdAt: now,
      updatedAt: now,
    })),
  );

  await db.insert(note).values(
    notes.map((item) => ({
      ...item,
      createdAt: now,
      updatedAt: now,
    })),
  );
}

export async function seed() {
  const adminUserId = await seedAuthAdmin();
  await seedRolesAndPermissions(adminUserId);
  await seedMonitoringData();
}

if (import.meta.main) {
  seed()
    .then(() => {
      console.info("Seeded auth admin and monitoring dashboard sample data.");
      console.info("Admin login: admin@minmon.local / admin12345");
      process.exit(0);
    })
    .catch((error) => {
      console.error("Failed to seed dashboard sample data.", error);
      process.exit(1);
    });
}
