-- =============================================================================
-- HOTEL RESERVATIONS — DATA MART (STAR SCHEMA)
-- Target: Oracle (university lab schema)
-- =============================================================================

-- -----------------------------------------------------------------------------
-- ETL CONTROL TABLE
-- Tracks incremental load watermarks per entity.
-- -----------------------------------------------------------------------------

CREATE TABLE ETL_WATERMARK (
    entity_name     VARCHAR2(50)    NOT NULL,
    last_key        NUMBER(20,0)    DEFAULT 0   NOT NULL,
    last_run_ts     TIMESTAMP       DEFAULT SYSTIMESTAMP,
    CONSTRAINT pk_etl_wm PRIMARY KEY (entity_name)
);

INSERT INTO ETL_WATERMARK (entity_name, last_key) VALUES ('FACT_ROOM_BOOKING', 0);
COMMIT;

-- -----------------------------------------------------------------------------
-- STAGING TABLES
-- NiFi loads raw MySQL data here first; SCD logic runs in pure SQL after.
-- Truncated at the start of each ETL run.
-- -----------------------------------------------------------------------------

CREATE TABLE STG_HOTEL (
    hotel_id        NUMBER(10,0)    NOT NULL,
    chain_code      VARCHAR2(10),
    country_code    CHAR(2)         NOT NULL,
    star_code       NUMBER(1,0)     NOT NULL,
    code            VARCHAR2(20)    NOT NULL,
    name            VARCHAR2(150)   NOT NULL,
    city            VARCHAR2(100)   NOT NULL
);

-- -----------------------------------------------------------------------------
-- DIMENSION TABLES
-- -----------------------------------------------------------------------------

-- YYYYMMDD integer key — cheap date range predicates, no JOIN to calendar needed
CREATE TABLE DIM_DATE (
    date_key        NUMBER(8,0)         NOT NULL,
    full_date       DATE                NOT NULL,
    year            NUMBER(4,0)         NOT NULL,
    quarter         NUMBER(1,0)         NOT NULL,
    month           NUMBER(2,0)         NOT NULL,
    month_name      VARCHAR2(10)        NOT NULL,
    week_number     NUMBER(2,0)         NOT NULL,
    day_of_month    NUMBER(2,0)         NOT NULL,
    day_name        VARCHAR2(10)        NOT NULL,
    is_weekend      NUMBER(1,0)         NOT NULL,
    is_business_day NUMBER(1,0)         NOT NULL,
    season          VARCHAR2(10)        NOT NULL,
    CONSTRAINT pk_dim_date      PRIMARY KEY (date_key),
    CONSTRAINT ck_dim_date_wknd CHECK (is_weekend      IN (0,1)),
    CONSTRAINT ck_dim_date_bday CHECK (is_business_day IN (0,1))
);

-- SCD Type 1 — country attributes are stable; just overwrite if anything changes
CREATE TABLE DIM_COUNTRY (
    country_key NUMBER(10,0)    GENERATED ALWAYS AS IDENTITY,
    country_id  NUMBER(10,0)    NOT NULL,
    code        CHAR(2)         NOT NULL,
    name        VARCHAR2(100)   NOT NULL,
    currency    VARCHAR2(10)    NOT NULL,
    CONSTRAINT pk_dim_country   PRIMARY KEY (country_key),
    CONSTRAINT uq_dim_cntry_id  UNIQUE (country_id)
);

-- SCD Type 1 — star rating lookup, never changes
CREATE TABLE DIM_STAR_RATING (
    star_rating_key NUMBER(10,0)    GENERATED ALWAYS AS IDENTITY,
    star_rating_id  NUMBER(10,0)    NOT NULL,
    code            NUMBER(1,0)     NOT NULL,
    description     VARCHAR2(20)    NOT NULL,
    CONSTRAINT pk_dim_star      PRIMARY KEY (star_rating_key),
    CONSTRAINT uq_dim_star_id   UNIQUE (star_rating_id)
);

-- SCD Type 1 — chain name/code rarely changes; overwrite
CREATE TABLE DIM_HOTEL_CHAIN (
    hotel_chain_key NUMBER(10,0)    GENERATED ALWAYS AS IDENTITY,
    hotel_chain_id  NUMBER(10,0)    NOT NULL,
    code            VARCHAR2(10)    NOT NULL,
    name            VARCHAR2(100)   NOT NULL,
    CONSTRAINT pk_dim_chain     PRIMARY KEY (hotel_chain_key),
    CONSTRAINT uq_dim_chain_id  UNIQUE (hotel_chain_id)
);

-- SCD Type 2 — hotels can change star rating or chain affiliation over time.
-- source_hotel_id is the natural key from MySQL; hotel_key is the surrogate.
-- One hotel can have multiple rows; IS_CURRENT=1 row is the active version.
-- FACT_ROOM_BOOKING links to the hotel version current at check-in date.
CREATE TABLE DIM_HOTEL (
    hotel_key           NUMBER(10,0)    GENERATED ALWAYS AS IDENTITY,
    source_hotel_id     NUMBER(10,0)    NOT NULL,
    hotel_chain_key     NUMBER(10,0),
    country_key         NUMBER(10,0)    NOT NULL,
    star_rating_key     NUMBER(10,0)    NOT NULL,
    code                VARCHAR2(20)    NOT NULL,
    name                VARCHAR2(150)   NOT NULL,
    city                VARCHAR2(100)   NOT NULL,
    -- SCD2 versioning
    effective_date      DATE            NOT NULL,
    expiry_date         DATE,
    is_current          NUMBER(1,0)     DEFAULT 1   NOT NULL,
    CONSTRAINT pk_dim_hotel     PRIMARY KEY (hotel_key),
    CONSTRAINT ck_dh_current    CHECK (is_current IN (0,1)),
    CONSTRAINT fk_dh_chain      FOREIGN KEY (hotel_chain_key) REFERENCES DIM_HOTEL_CHAIN (hotel_chain_key),
    CONSTRAINT fk_dh_country    FOREIGN KEY (country_key)     REFERENCES DIM_COUNTRY     (country_key),
    CONSTRAINT fk_dh_star       FOREIGN KEY (star_rating_key) REFERENCES DIM_STAR_RATING (star_rating_key)
);

-- SCD Type 1 — room type/floor rarely changes; upsert is sufficient
CREATE TABLE DIM_ROOM (
    room_key        NUMBER(10,0)    GENERATED ALWAYS AS IDENTITY,
    room_id         NUMBER(10,0)    NOT NULL,
    hotel_key       NUMBER(10,0)    NOT NULL,
    room_number     VARCHAR2(10)    NOT NULL,
    floor           NUMBER(3,0)     NOT NULL,
    room_type_code  VARCHAR2(20)    NOT NULL,
    room_type_desc  VARCHAR2(100)   NOT NULL,
    smoking_yn      NUMBER(1,0)     NOT NULL,
    standard_rate   NUMBER(10,2)    NOT NULL,
    CONSTRAINT pk_dim_room      PRIMARY KEY (room_key),
    CONSTRAINT uq_dim_room_id   UNIQUE (room_id),
    CONSTRAINT fk_dr_hotel      FOREIGN KEY (hotel_key) REFERENCES DIM_HOTEL (hotel_key),
    CONSTRAINT ck_dim_room_smk  CHECK (smoking_yn IN (0,1))
);

-- SCD Type 1 — guest contact details are overwritten if they change
CREATE TABLE DIM_GUEST (
    guest_key   NUMBER(10,0)    GENERATED ALWAYS AS IDENTITY,
    guest_id    NUMBER(10,0)    NOT NULL,
    country_key NUMBER(10,0),
    name        VARCHAR2(150)   NOT NULL,
    city        VARCHAR2(100),
    CONSTRAINT pk_dim_guest     PRIMARY KEY (guest_key),
    CONSTRAINT uq_dim_guest_id  UNIQUE (guest_id),
    CONSTRAINT fk_dg_country    FOREIGN KEY (country_key) REFERENCES DIM_COUNTRY (country_key)
);

-- -----------------------------------------------------------------------------
-- FACT TABLE
-- -----------------------------------------------------------------------------

-- Grain: one row per room_booking.
-- source_rb_id: natural key from MySQL — used for idempotent incremental loads.
-- hotel_key: points to the DIM_HOTEL version active at check-in (SCD2 lookup).
CREATE TABLE FACT_ROOM_BOOKING (
    fact_id             NUMBER(10,0)    GENERATED ALWAYS AS IDENTITY,
    source_rb_id        NUMBER(10,0)    NOT NULL,
    -- dimension FKs
    hotel_key           NUMBER(10,0)    NOT NULL,
    hotel_chain_key     NUMBER(10,0),
    room_key            NUMBER(10,0)    NOT NULL,
    guest_key           NUMBER(10,0)    NOT NULL,
    country_key         NUMBER(10,0),
    star_rating_key     NUMBER(10,0)    NOT NULL,
    checkin_date_key    NUMBER(8,0)     NOT NULL,
    checkout_date_key   NUMBER(8,0)     NOT NULL,
    -- degenerate dimension
    booking_status      VARCHAR2(20)    NOT NULL,
    -- measures
    nights_stayed       NUMBER(4,0)     NOT NULL,
    nightly_rate        NUMBER(10,2)    NOT NULL,
    total_amount        NUMBER(12,2)    NOT NULL,
    CONSTRAINT pk_fact_rb       PRIMARY KEY (fact_id),
    CONSTRAINT uq_fact_rb_src   UNIQUE (source_rb_id),
    CONSTRAINT fk_frb_hotel     FOREIGN KEY (hotel_key)        REFERENCES DIM_HOTEL       (hotel_key),
    CONSTRAINT fk_frb_chain     FOREIGN KEY (hotel_chain_key)  REFERENCES DIM_HOTEL_CHAIN (hotel_chain_key),
    CONSTRAINT fk_frb_room      FOREIGN KEY (room_key)         REFERENCES DIM_ROOM        (room_key),
    CONSTRAINT fk_frb_guest     FOREIGN KEY (guest_key)        REFERENCES DIM_GUEST       (guest_key),
    CONSTRAINT fk_frb_country   FOREIGN KEY (country_key)      REFERENCES DIM_COUNTRY     (country_key),
    CONSTRAINT fk_frb_star      FOREIGN KEY (star_rating_key)  REFERENCES DIM_STAR_RATING (star_rating_key),
    CONSTRAINT fk_frb_checkin   FOREIGN KEY (checkin_date_key)  REFERENCES DIM_DATE (date_key),
    CONSTRAINT fk_frb_checkout  FOREIGN KEY (checkout_date_key) REFERENCES DIM_DATE (date_key)
);
