import {
  bigint,
  foreignKey,
  pgEnum,
  pgTable,
  text,
  timestamp,
  unique,
  uuid,
} from "drizzle-orm/pg-core";
import { portfolio } from "./portfolio";

// Enum string values mirror /workspaces/home/github/Model/domain/landlord_description_overrides/*.py
// exactly (PropertyType.value, WallType.value, BuiltFormType.value, RoofType.value). Keep in sync — see
// docs/adr/0002-landlord-override-vocabulary.md.
export const PropertyTypeValues: [string, ...string[]] = [
  "House",
  "Bungalow",
  "Flat",
  "Maisonette",
  "Park home",
  "Unknown",
];

export const WallTypeValues: [string, ...string[]] = [
  "Cavity wall, filled cavity",
  "Cavity wall, as built, insulated (assumed)",
  "Cavity wall, as built, no insulation (assumed)",
  "Cavity wall, as built, partial insulation (assumed)",
  "Cavity wall, with internal insulation",
  "Cavity wall, with external insulation",
  "Cavity wall, filled cavity and internal insulation",
  "Cavity wall, filled cavity and external insulation",
  "Solid brick, as built, no insulation (assumed)",
  "Solid brick, as built, insulated (assumed)",
  "Solid brick, as built, partial insulation (assumed)",
  "Solid brick, with internal insulation",
  "Solid brick, with external insulation",
  "Timber frame, as built, no insulation (assumed)",
  "Timber frame, as built, insulated (assumed)",
  "Timber frame, as built, partial insulation (assumed)",
  "Timber frame, with additional insulation",
  "Sandstone, as built, no insulation (assumed)",
  "Sandstone, as built, insulated (assumed)",
  "Sandstone, as built, partial insulation (assumed)",
  "Sandstone, with internal insulation",
  "Sandstone, with external insulation",
  "Granite or whin, as built, no insulation (assumed)",
  "Granite or whin, as built, insulated (assumed)",
  "Granite or whin, as built, partial insulation (assumed)",
  "Granite or whin, with internal insulation",
  "Granite or whin, with external insulation",
  "System built, as built, no insulation (assumed)",
  "System built, as built, insulated (assumed)",
  "System built, as built, partial insulation (assumed)",
  "System built, with internal insulation",
  "System built, with external insulation",
  "Park home wall, as built",
  "Park home wall, with internal insulation",
  "Park home wall, with external insulation",
  "Cob, as built",
  "Cob, with internal insulation",
  "Cob, with external insulation",
  "Curtain wall",
  "Curtain Wall, as built, no insulation (assumed)",
  "Curtain Wall, as built, insulated (assumed)",
  "Curtain Wall, filled cavity",
  "Curtain Wall, with internal insulation",
  "Basement wall",
  "Basement wall, as built",
  "Unknown",
];

export const BuiltFormTypeValues: [string, ...string[]] = [
  "Detached",
  "Semi-Detached",
  "Mid-Terrace",
  "End-Terrace",
  "Enclosed Mid-Terrace",
  "Enclosed End-Terrace",
  "Not Recorded",
  "Unknown",
];

export const RoofTypeValues: [string, ...string[]] = [
  "Flat, insulated",
  "Flat, insulated (assumed)",
  "Flat, limited insulation",
  "Flat, limited insulation (assumed)",
  "Flat, no insulation",
  "Flat, no insulation (assumed)",
  "Flat, 12 mm insulation",
  "Flat, 25 mm insulation",
  "Flat, 50 mm insulation",
  "Flat, 75 mm insulation",
  "Flat, 100 mm insulation",
  "Flat, 125 mm insulation",
  "Flat, 150 mm insulation",
  "Flat, 175 mm insulation",
  "Flat, 200 mm insulation",
  "Flat, 225 mm insulation",
  "Flat, 250 mm insulation",
  "Flat, 270 mm insulation",
  "Flat, 300 mm insulation",
  "Flat, 350 mm insulation",
  "Flat, 400 mm insulation",
  "Flat, 400+ mm insulation",
  "Pitched, insulated",
  "Pitched, insulated (assumed)",
  "Pitched, insulated at rafters",
  "Pitched, limited insulation",
  "Pitched, limited insulation (assumed)",
  "Pitched, no insulation",
  "Pitched, no insulation (assumed)",
  "Pitched, Unknown loft insulation",
  "Pitched, 0 mm loft insulation",
  "Pitched, 12 mm loft insulation",
  "Pitched, 25 mm loft insulation",
  "Pitched, 50 mm loft insulation",
  "Pitched, 75 mm loft insulation",
  "Pitched, 100 mm loft insulation",
  "Pitched, 125 mm loft insulation",
  "Pitched, 150 mm loft insulation",
  "Pitched, 175 mm loft insulation",
  "Pitched, 200 mm loft insulation",
  "Pitched, 225 mm loft insulation",
  "Pitched, 250 mm loft insulation",
  "Pitched, 270 mm loft insulation",
  "Pitched, 300 mm loft insulation",
  "Pitched, 350 mm loft insulation",
  "Pitched, 400 mm loft insulation",
  "Pitched, 400+ mm loft insulation",
  "Roof room(s), insulated",
  "Roof room(s), insulated (assumed)",
  "Roof room(s), limited insulation",
  "Roof room(s), limited insulation (assumed)",
  "Roof room(s), no insulation",
  "Roof room(s), no insulation (assumed)",
  "Roof room(s), ceiling insulated",
  "Roof room(s), thatched",
  "Roof room(s), thatched with additional insulation",
  "Thatched",
  "Thatched, with additional insulation",
  "(another dwelling above)",
  "(same dwelling above)",
  "(other premises above)",
  "(another premises above)",
  "Another Premises Above",
  "Unknown",
];

// Mirrors MainFuelType.value (domain/epc/main_fuel_type.py). Each value is the
// canonical fuel description the main-fuel Simulation Overlay decomposes into the
// RdSAP main_fuel int code. Keep in sync — see docs/adr/0002-landlord-override-vocabulary.md.
export const MainFuelValues: [string, ...string[]] = [
  "mains gas",
  "mains gas (community)",
  "electricity",
  "electricity (community)",
  "LPG (bulk)",
  "bottled LPG",
  "LPG special condition",
  "oil",
  "house coal",
  "smokeless coal",
  "dual fuel (mineral and wood)",
  "biomass (community)",
  "wood logs",
  "Unknown",
];

// Mirrors GlazingType.value (domain/epc/glazing_type.py). Each value is the
// canonical glazing description (type + era) the glazing Simulation Overlay
// decomposes into the SAP10 glazing_type code. Keep in sync — see
// docs/adr/0002-landlord-override-vocabulary.md.
export const GlazingValues: [string, ...string[]] = [
  "Single glazing",
  "Double glazing, 2002 or later",
  "Double glazing, pre-2002",
  "Triple glazing, pre-2002",
  "Triple glazing, 2002 or later",
  "Mixed glazing",
  "Secondary glazing",
  "Unknown",
];

// Mirrors ConstructionAgeBand.value (domain/epc/construction_age_band.py): the
// RdSAP England-&-Wales age-band letter codes A..M the calculator reads. Keep in
// sync — see docs/adr/0002-landlord-override-vocabulary.md.
export const ConstructionAgeBandValues: [string, ...string[]] = [
  "A",
  "B",
  "C",
  "D",
  "E",
  "F",
  "G",
  "H",
  "I",
  "J",
  "K",
  "L",
  "M",
  "Unknown",
];

// Mirrors WaterHeatingType.value (domain/epc/water_heating_type.py): "<system>,
// <fuel>" descriptions the water-heating overlay decomposes into
// water_heating_code + water_heating_fuel. Keep in sync — see
// docs/adr/0002-landlord-override-vocabulary.md.
export const WaterHeatingValues: [string, ...string[]] = [
  "From main system, mains gas",
  "From main system, electricity",
  "From main system, oil",
  "From main system, LPG (bulk)",
  "From main system, bottled LPG",
  "From main system, house coal",
  "Electric immersion, electricity",
  "Gas boiler/circulator, mains gas",
  "From main system, wood logs",
  "From main system, biomass (community)",
  "From main system, dual fuel (mineral and wood)",
  "From main system, biodiesel (community)",
  "Unknown",
];

// Mirrors MainHeatingSystemType.value (domain/epc/main_heating_system_type.py):
// system archetypes the main-heating overlay maps to a sap_main_heating_code.
// Keep in sync — see docs/adr/0002-landlord-override-vocabulary.md.
export const MainHeatingSystemValues: [string, ...string[]] = [
  "Gas boiler, combi",
  "Gas boiler, regular",
  "Gas CPSU",
  "Electric storage heaters, old",
  "Electric storage heaters, slimline",
  "Electric storage heaters, convector",
  "Electric storage heaters, fan",
  "Direct-acting electric",
  "Electric room heaters",
  "Solid fuel room heater, closed",
  "Air source heat pump",
  "Community heating, boilers",
  "Community heating, CHP and boilers",
  "Oil room heater, 2000 or later",
  "Gas room heater, condensing fire",
  "Gas room heater, decorative fuel-effect",
  "Gas room heater, flush live-effect",
  "Gas room heater, open flue 1980 or later",
  "Gas room heater, open flue pre-1980",
  "Electric storage heaters, high heat retention",
  "Solid fuel room heater, open fire",
  "Solid fuel room heater, open fire with back boiler",
  "Solid fuel room heater, closed with boiler",
  "Electric boiler",
  "Electric CPSU",
  "Electric underfloor, in concrete slab (off-peak)",
  "Electric underfloor, integrated storage and direct-acting",
  "Electric underfloor, in screed above insulation",
  "Unknown",
];

export const OverrideSourceValues: [string, ...string[]] = [
  "classifier",
  "user",
  // Deterministic OS Places classification-code mapping (postcode search, ADR-0007)
  "os_places",
];

export const propertyTypeEnum = pgEnum("property_type", PropertyTypeValues);
export const wallTypeEnum = pgEnum("wall_type", WallTypeValues);
export const builtFormTypeEnum = pgEnum("built_form_type", BuiltFormTypeValues);
export const roofTypeEnum = pgEnum("roof_type", RoofTypeValues);
export const mainFuelEnum = pgEnum("main_fuel", MainFuelValues);
export const glazingEnum = pgEnum("glazing", GlazingValues);
export const constructionAgeBandEnum = pgEnum(
  "construction_age_band",
  ConstructionAgeBandValues,
);
export const waterHeatingEnum = pgEnum("water_heating", WaterHeatingValues);
export const mainHeatingSystemEnum = pgEnum(
  "main_heating_system",
  MainHeatingSystemValues,
);
export const overrideSourceEnum = pgEnum(
  "override_source",
  OverrideSourceValues,
);

export const landlordPropertyTypeOverrides = pgTable(
  "landlord_property_type_overrides",
  {
    id: uuid("id").defaultRandom().primaryKey(),
    portfolioId: bigint("portfolio_id", { mode: "bigint" })
      .notNull()
      .references(() => portfolio.id, { onDelete: "cascade" }),
    description: text("description").notNull(),
    value: propertyTypeEnum("value").notNull(),
    source: overrideSourceEnum("source").notNull(),
    createdAt: timestamp("created_at", { withTimezone: true })
      .notNull()
      .defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true })
      .notNull()
      .defaultNow()
      .$onUpdate(() => new Date()),
  },
  (table) => ({
    portfolioDescriptionUnique: unique(
      "landlord_property_type_overrides_portfolio_description_unique",
    ).on(table.portfolioId, table.description),
  }),
);

export const landlordWallTypeOverrides = pgTable(
  "landlord_wall_type_overrides",
  {
    id: uuid("id").defaultRandom().primaryKey(),
    portfolioId: bigint("portfolio_id", { mode: "bigint" })
      .notNull()
      .references(() => portfolio.id, { onDelete: "cascade" }),
    description: text("description").notNull(),
    value: wallTypeEnum("value").notNull(),
    source: overrideSourceEnum("source").notNull(),
    createdAt: timestamp("created_at", { withTimezone: true })
      .notNull()
      .defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true })
      .notNull()
      .defaultNow()
      .$onUpdate(() => new Date()),
  },
  (table) => ({
    portfolioDescriptionUnique: unique(
      "landlord_wall_type_overrides_portfolio_description_unique",
    ).on(table.portfolioId, table.description),
  }),
);

export const landlordBuiltFormTypeOverrides = pgTable(
  "landlord_built_form_type_overrides",
  {
    id: uuid("id").defaultRandom().primaryKey(),
    portfolioId: bigint("portfolio_id", { mode: "bigint" })
      .notNull()
      .references(() => portfolio.id, { onDelete: "cascade" }),
    description: text("description").notNull(),
    value: builtFormTypeEnum("value").notNull(),
    source: overrideSourceEnum("source").notNull(),
    createdAt: timestamp("created_at", { withTimezone: true })
      .notNull()
      .defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true })
      .notNull()
      .defaultNow()
      .$onUpdate(() => new Date()),
  },
  (table) => ({
    portfolioDescriptionUnique: unique(
      "landlord_built_form_type_overrides_portfolio_description_unique",
    ).on(table.portfolioId, table.description),
  }),
);

export const landlordRoofTypeOverrides = pgTable(
  "landlord_roof_type_overrides",
  {
    id: uuid("id").defaultRandom().primaryKey(),
    portfolioId: bigint("portfolio_id", { mode: "bigint" })
      .notNull()
      .references(() => portfolio.id, { onDelete: "cascade" }),
    description: text("description").notNull(),
    value: roofTypeEnum("value").notNull(),
    source: overrideSourceEnum("source").notNull(),
    createdAt: timestamp("created_at", { withTimezone: true })
      .notNull()
      .defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true })
      .notNull()
      .defaultNow()
      .$onUpdate(() => new Date()),
  },
  (table) => ({
    portfolioDescriptionUnique: unique(
      "landlord_roof_type_overrides_portfolio_description_unique",
    ).on(table.portfolioId, table.description),
  }),
);

export const landlordMainFuelOverrides = pgTable(
  "landlord_main_fuel_overrides",
  {
    id: uuid("id").defaultRandom().primaryKey(),
    portfolioId: bigint("portfolio_id", { mode: "bigint" })
      .notNull()
      .references(() => portfolio.id, { onDelete: "cascade" }),
    description: text("description").notNull(),
    value: mainFuelEnum("value").notNull(),
    source: overrideSourceEnum("source").notNull(),
    createdAt: timestamp("created_at", { withTimezone: true })
      .notNull()
      .defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true })
      .notNull()
      .defaultNow()
      .$onUpdate(() => new Date()),
  },
  (table) => ({
    portfolioDescriptionUnique: unique(
      "landlord_main_fuel_overrides_portfolio_description_unique",
    ).on(table.portfolioId, table.description),
  }),
);

export const landlordGlazingOverrides = pgTable(
  "landlord_glazing_overrides",
  {
    id: uuid("id").defaultRandom().primaryKey(),
    portfolioId: bigint("portfolio_id", { mode: "bigint" })
      .notNull()
      .references(() => portfolio.id, { onDelete: "cascade" }),
    description: text("description").notNull(),
    value: glazingEnum("value").notNull(),
    source: overrideSourceEnum("source").notNull(),
    createdAt: timestamp("created_at", { withTimezone: true })
      .notNull()
      .defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true })
      .notNull()
      .defaultNow()
      .$onUpdate(() => new Date()),
  },
  (table) => ({
    portfolioDescriptionUnique: unique(
      "landlord_glazing_overrides_portfolio_description_unique",
    ).on(table.portfolioId, table.description),
  }),
);

export const landlordConstructionAgeBandOverrides = pgTable(
  "landlord_construction_age_band_overrides",
  {
    id: uuid("id").defaultRandom().primaryKey(),
    // FK defined in the table config below with an explicit short name (the
    // default derived name overflows Postgres's 63-char identifier limit).
    portfolioId: bigint("portfolio_id", { mode: "bigint" }).notNull(),
    description: text("description").notNull(),
    value: constructionAgeBandEnum("value").notNull(),
    source: overrideSourceEnum("source").notNull(),
    createdAt: timestamp("created_at", { withTimezone: true })
      .notNull()
      .defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true })
      .notNull()
      .defaultNow()
      .$onUpdate(() => new Date()),
  },
  (table) => ({
    // Both names shortened to stay within PostgreSQL's 63-char identifier limit
    // (the default derived names are 68/69 chars); mirror
    // LandlordConstructionAgeBandOverrideRow.
    portfolioFk: foreignKey({
      columns: [table.portfolioId],
      foreignColumns: [portfolio.id],
      name: "landlord_construction_age_band_overrides_portfolio_fk",
    }).onDelete("cascade"),
    portfolioDescriptionUnique: unique(
      "landlord_construction_age_band_portfolio_description_unique",
    ).on(table.portfolioId, table.description),
  }),
);

export const landlordWaterHeatingOverrides = pgTable(
  "landlord_water_heating_overrides",
  {
    id: uuid("id").defaultRandom().primaryKey(),
    portfolioId: bigint("portfolio_id", { mode: "bigint" })
      .notNull()
      .references(() => portfolio.id, { onDelete: "cascade" }),
    description: text("description").notNull(),
    value: waterHeatingEnum("value").notNull(),
    source: overrideSourceEnum("source").notNull(),
    createdAt: timestamp("created_at", { withTimezone: true })
      .notNull()
      .defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true })
      .notNull()
      .defaultNow()
      .$onUpdate(() => new Date()),
  },
  (table) => ({
    portfolioDescriptionUnique: unique(
      "landlord_water_heating_overrides_portfolio_description_unique",
    ).on(table.portfolioId, table.description),
  }),
);

export const landlordMainHeatingSystemOverrides = pgTable(
  "landlord_main_heating_system_overrides",
  {
    id: uuid("id").defaultRandom().primaryKey(),
    // FK in the table config below with an explicit short name (the default
    // derived name overflows Postgres's 63-char identifier limit).
    portfolioId: bigint("portfolio_id", { mode: "bigint" }).notNull(),
    description: text("description").notNull(),
    value: mainHeatingSystemEnum("value").notNull(),
    source: overrideSourceEnum("source").notNull(),
    createdAt: timestamp("created_at", { withTimezone: true })
      .notNull()
      .defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true })
      .notNull()
      .defaultNow()
      .$onUpdate(() => new Date()),
  },
  (table) => ({
    // Both names shortened to stay within Postgres's 63-char identifier limit;
    // mirror LandlordMainHeatingSystemOverrideRow.
    portfolioFk: foreignKey({
      columns: [table.portfolioId],
      foreignColumns: [portfolio.id],
      name: "landlord_main_heating_system_overrides_portfolio_fk",
    }).onDelete("cascade"),
    portfolioDescriptionUnique: unique(
      "landlord_main_heating_system_portfolio_description_unique",
    ).on(table.portfolioId, table.description),
  }),
);
