-- pf.dim_period — create and populate
-- Adjust fiscal_start_month: 1=Jan (calendar year), 4=Apr, 6=Jun, 7=Jul, 10=Oct, etc.
-- Safe to re-run: ON CONFLICT DO NOTHING, so existing rows are never overwritten.

CREATE TABLE IF NOT EXISTS pf.dim_period (
    sdat                date        NOT NULL PRIMARY KEY,
    edat                date        NOT NULL,
    drange              daterange   NOT NULL,
    ndays               integer     NOT NULL,
    -- calendar
    cal_year            integer     NOT NULL,
    cal_quarter         integer     NOT NULL,
    cal_month           integer     NOT NULL,
    cal_month_abbr      text        NOT NULL,   -- 01 - Jan
    cal_month_name      text        NOT NULL,   -- 01 - January
    cal_label           text        NOT NULL,   -- 2025-01 Jan
    -- fiscal
    fisc_year           integer     NOT NULL,
    fisc_quarter        integer     NOT NULL,
    fisc_quarter_label  text        NOT NULL,   -- FY2025 Q3
    fisc_month          integer     NOT NULL,
    fisc_month_abbr     text        NOT NULL,   -- 07 - Jan
    fisc_month_name     text        NOT NULL,   -- 07 - January
    fisc_label          text        NOT NULL,   -- FY2025 P07
    -- sort key
    period_key          text        NOT NULL    -- 2025.07  (ltree-compatible)
);

CREATE INDEX IF NOT EXISTS dim_period_drange_idx ON pf.dim_period USING gist (drange);
CREATE INDEX IF NOT EXISTS dim_period_fisc_idx   ON pf.dim_period (fisc_year, fisc_month);
CREATE INDEX IF NOT EXISTS dim_period_cal_idx    ON pf.dim_period (cal_year,  cal_month);

WITH
cfg AS (
    SELECT 6 AS fiscal_start_month  -- change to match your fiscal year start month
)
,periods AS (
    SELECT
        gs.d::date                                      AS sdat,
        (gs.d + '1 month'::interval)::date              AS edat,
        extract(year  FROM gs.d)::int                   AS cal_year,
        extract(month FROM gs.d)::int                   AS cal_month,
        extract(quarter FROM gs.d)::int                 AS cal_quarter,
        ((extract(month FROM gs.d)::int - cfg.fiscal_start_month + 12) % 12) + 1
                                                        AS fisc_month,
        extract(year FROM gs.d)::int
            + CASE
                WHEN cfg.fiscal_start_month > 1
                 AND extract(month FROM gs.d)::int >= cfg.fiscal_start_month
                THEN 1 ELSE 0
              END                                       AS fisc_year
    FROM
        generate_series('2018-01-01'::date, '2035-12-01'::date, '1 month') gs(d)
        CROSS JOIN cfg
)
INSERT INTO pf.dim_period (
    sdat, edat, drange, ndays,
    cal_year, cal_quarter, cal_month,
    cal_month_abbr, cal_month_name, cal_label,
    fisc_year, fisc_quarter, fisc_quarter_label,
    fisc_month, fisc_month_abbr, fisc_month_name,
    fisc_label, period_key
)
SELECT
    sdat,
    edat,
    daterange(sdat, edat)                                               AS drange,
    edat - sdat                                                         AS ndays,
    cal_year,
    cal_quarter,
    cal_month,
    to_char(cal_month,  'FM00') || ' - ' || to_char(sdat, 'Mon')       AS cal_month_abbr,
    to_char(cal_month,  'FM00') || ' - ' || to_char(sdat, 'Month')     AS cal_month_name,
    to_char(sdat, 'YYYY-MM') || ' ' || to_char(sdat, 'Mon')            AS cal_label,
    fisc_year,
    ceil(fisc_month / 3.0)::int                                         AS fisc_quarter,
    'FY' || fisc_year || ' Q' || ceil(fisc_month / 3.0)::int           AS fisc_quarter_label,
    fisc_month,
    to_char(fisc_month, 'FM00') || ' - ' || to_char(sdat, 'Mon')       AS fisc_month_abbr,
    to_char(fisc_month, 'FM00') || ' - ' || to_char(sdat, 'Month')     AS fisc_month_name,
    'FY' || fisc_year || ' P' || to_char(fisc_month, 'FM00')           AS fisc_label,
    to_char(fisc_year, 'FM0000') || '.' || to_char(fisc_month, 'FM00') AS period_key
FROM periods
ON CONFLICT (sdat) DO NOTHING;

-- preview first 24 months
SELECT
    period_key, sdat, edat, ndays,
    cal_year, cal_quarter, cal_month, cal_month_abbr,
    fisc_year, fisc_quarter, fisc_month, fisc_month_abbr,
    fisc_quarter_label, fisc_label, cal_label
FROM pf.dim_period
ORDER BY sdat
LIMIT 24;
