import bcrypt from "bcryptjs";

import { env } from "../config/env.js";
import { pool } from "./pool.js";
import { runMigrations } from "./migrate.js";

type UserSeed = {
  name: string;
  email: string;
  role: "admin" | "operator" | "viewer";
  password: string;
};

type CategorySeed = {
  name: string;
  items: Array<{
    name: string;
    serialNumber: string;
    assetTag: string;
    suggestedDayRate: number;
    status?: "active" | "service" | "retired";
    notes?: string;
    hidden?: boolean;
  }>;
};

const users: UserSeed[] = [
  {
    name: env.ADMIN_NAME,
    email: env.ADMIN_EMAIL,
    role: "admin",
    password: env.ADMIN_PASSWORD
  },
  {
    name: "Katarzyna Operator",
    email: "operator@rental.local",
    role: "operator",
    password: "Operator123!"
  },
  {
    name: "Marek Viewer",
    email: "viewer@rental.local",
    role: "viewer",
    password: "Viewer123!"
  }
];

const categories: CategorySeed[] = [
  {
    name: "Laptopy",
    items: [
      { name: "Dell Latitude 14 A", serialNumber: "DL14-001", assetTag: "L14-001", suggestedDayRate: 140 },
      { name: "Dell Latitude 14 B", serialNumber: "DL14-002", assetTag: "L14-002", suggestedDayRate: 140 },
      { name: "HP EliteBook 14 C", serialNumber: "HP14-003", assetTag: "L14-003", suggestedDayRate: 145 },
      { name: "HP ProBook 15 A", serialNumber: "HP15-001", assetTag: "L15-001", suggestedDayRate: 155 },
      { name: "HP ProBook 15 B", serialNumber: "HP15-002", assetTag: "L15-002", suggestedDayRate: 155 },
      { name: "Dell Vostro 15 C", serialNumber: "DL15-003", assetTag: "L15-003", suggestedDayRate: 150 },
      { name: "Lenovo Legion 15.4 A", serialNumber: "LEG-001", assetTag: "LEG-001", suggestedDayRate: 185 },
      { name: "Lenovo Legion 15.4 B", serialNumber: "LEG-002", assetTag: "LEG-002", suggestedDayRate: 185, status: "service", notes: "Wymiana klawiatury" },
      { name: "MacBook Pro 14 A", serialNumber: "MBP-001", assetTag: "MBP-001", suggestedDayRate: 220 },
      { name: "MacBook Pro 14 B", serialNumber: "MBP-002", assetTag: "MBP-002", suggestedDayRate: 220 }
    ]
  },
  {
    name: "Tablety",
    items: [
      { name: "Samsung Tab A", serialNumber: "SAMTAB-001", assetTag: "TAB-S-001", suggestedDayRate: 85 },
      { name: "Samsung Tab B", serialNumber: "SAMTAB-002", assetTag: "TAB-S-002", suggestedDayRate: 85 },
      { name: "iPad 10 A", serialNumber: "IPAD-001", assetTag: "TAB-I-001", suggestedDayRate: 95 },
      { name: "iPad 10 B", serialNumber: "IPAD-002", assetTag: "TAB-I-002", suggestedDayRate: 95 },
      { name: "iPad Pro 11 A", serialNumber: "IPADPRO-001", assetTag: "TAB-P-001", suggestedDayRate: 120 },
      { name: "iPad Pro 11 B", serialNumber: "IPADPRO-002", assetTag: "TAB-P-002", suggestedDayRate: 120 }
    ]
  },
  {
    name: "Akcesoria",
    items: [
      { name: "Monitor 21.5 A", serialNumber: "MON215-001", assetTag: "MON-215-001", suggestedDayRate: 40 },
      { name: "Monitor 21.5 B", serialNumber: "MON215-002", assetTag: "MON-215-002", suggestedDayRate: 40 },
      { name: "Monitor 24 A", serialNumber: "MON24-001", assetTag: "MON-24-001", suggestedDayRate: 45 },
      { name: "Monitor 24 B", serialNumber: "MON24-002", assetTag: "MON-24-002", suggestedDayRate: 45 },
      { name: "Spotlight A", serialNumber: "SPOT-001", assetTag: "ACC-001", suggestedDayRate: 25 },
      { name: "Spotlight B", serialNumber: "SPOT-002", assetTag: "ACC-002", suggestedDayRate: 25, status: "retired", hidden: true, notes: "Zużyta bateria" }
    ]
  }
];

const dateFromOffset = (offset: number) => {
  const base = new Date();
  base.setHours(12, 0, 0, 0);
  base.setDate(base.getDate() + offset);
  return base.toISOString().slice(0, 10);
};

export const seedDatabase = async (options?: { reset?: boolean }) => {
  if (options?.reset) {
    await pool.query(`
      truncate table rental_bookings, equipment_items, equipment_categories, users
      restart identity cascade
    `);
  }

  const client = await pool.connect();

  try {
    await client.query("begin");

    const userMap = new Map<string, string>();

    for (const user of users) {
      const passwordHash = await bcrypt.hash(user.password, 10);
      const inserted = await client.query<{ id: string }>(
        `
          insert into users (name, email, password_hash, role, is_active)
          values ($1, $2, $3, $4, true)
          on conflict (email) do update
            set name = excluded.name,
                password_hash = excluded.password_hash,
                role = excluded.role,
                is_active = true,
                updated_at = now()
          returning id
        `,
        [user.name, user.email, passwordHash, user.role]
      );

      const insertedUser = inserted.rows[0];

      if (!insertedUser) {
        throw new Error(`Failed to upsert user ${user.email}`);
      }

      userMap.set(user.email, insertedUser.id);
    }

    const itemMap = new Map<string, string>();

    for (const category of categories) {
      const categoryResult = await client.query<{ id: string }>(
        `
          insert into equipment_categories (name)
          values ($1)
          on conflict (name) do update
            set updated_at = now()
          returning id
        `,
        [category.name]
      );

      const insertedCategory = categoryResult.rows[0];

      if (!insertedCategory) {
        throw new Error(`Failed to upsert category ${category.name}`);
      }

      const categoryId = insertedCategory.id;

      for (const item of category.items) {
        const itemResult = await client.query<{ id: string }>(
          `
            insert into equipment_items (
              category_id,
              name,
              serial_number,
              asset_tag,
              suggested_day_rate,
              status,
              notes,
              is_visible_on_timeline
            )
            values ($1, $2, $3, $4, $5, $6, $7, $8)
            on conflict (asset_tag) do update
              set category_id = excluded.category_id,
                  name = excluded.name,
                  serial_number = excluded.serial_number,
                  suggested_day_rate = excluded.suggested_day_rate,
                  status = excluded.status,
                  notes = excluded.notes,
                  is_visible_on_timeline = excluded.is_visible_on_timeline,
                  updated_at = now()
            returning id
          `,
          [
            categoryId,
            item.name,
            item.serialNumber,
            item.assetTag,
            item.suggestedDayRate,
            item.status ?? "active",
            item.notes ?? null,
            item.hidden ? false : true
          ]
        );

        const insertedItem = itemResult.rows[0];

        if (!insertedItem) {
          throw new Error(`Failed to upsert item ${item.name}`);
        }

        itemMap.set(item.assetTag, insertedItem.id);
      }
    }

    const adminId = userMap.get(env.ADMIN_EMAIL) ?? null;
    const operatorId = userMap.get("operator@rental.local") ?? adminId;

    await client.query("delete from rental_bookings");

    const bookings = [
      { assetTag: "L14-001", customer: "Acme Events", start: -2, end: 4, project: "Roadshow Q2", order: "ZAM-1001" },
      { assetTag: "L15-001", customer: "Orange Expo", start: 3, end: 8, project: "Konferencja handlowa", order: "ZAM-1002" },
      { assetTag: "LEG-001", customer: "Pixel Forge", start: 9, end: 14, project: "Turniej gamingowy", order: "ZAM-1003" },
      { assetTag: "MBP-001", customer: "Studio Echo", start: -6, end: -1, project: "Postprodukcja", order: "ZAM-1004" },
      { assetTag: "TAB-S-001", customer: "Focus Media", start: 1, end: 6, project: "Badanie ankietowe", order: "ZAM-1005" },
      { assetTag: "TAB-I-001", customer: "Eventline", start: 5, end: 11, project: "Recepcja mobilna", order: "ZAM-1006" },
      { assetTag: "TAB-P-001", customer: "Boardroom", start: -4, end: 2, project: "Demo premium", order: "ZAM-1007" },
      { assetTag: "MON-24-001", customer: "Trade Group", start: 0, end: 3, project: "Stoisko targowe", order: "ZAM-1008" },
      { assetTag: "ACC-001", customer: "Visio Labs", start: 7, end: 10, project: "Prezentacja dla zarządu", order: "ZAM-1009" }
    ];

    for (const booking of bookings) {
      const equipmentItemId = itemMap.get(booking.assetTag);

      if (!equipmentItemId) {
        continue;
      }

      await client.query(
        `
          insert into rental_bookings (
            equipment_item_id,
            customer_name,
            order_number,
            project_name,
            notes,
            start_date,
            end_date,
            created_by
          )
          values ($1, $2, $3, $4, $5, $6, $7, $8)
        `,
        [
          equipmentItemId,
          booking.customer,
          booking.order,
          booking.project,
          "Seed demo reservation",
          dateFromOffset(booking.start),
          dateFromOffset(booking.end),
          operatorId
        ]
      );
    }

    await client.query("commit");
  } catch (error) {
    await client.query("rollback");
    throw error;
  } finally {
    client.release();
  }
};

if (process.argv[1] && process.argv[1].endsWith("seed.ts")) {
  runMigrations()
    .then(() => seedDatabase({ reset: true }))
    .then(async () => {
      await pool.end();
    })
    .catch(async (error) => {
      console.error(error);
      await pool.end();
      process.exit(1);
    });
}
