-- SEAP Data Schema for Harta Banilor Publici
-- Runs inside architools_db, isolated in schema "seap"
-- ZERO modifications to existing public.* tables

BEGIN;

-- Enable extensions needed for fuzzy matching
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS unaccent;

CREATE SCHEMA IF NOT EXISTS seap;

-- ── Entități SEAP (autorități contractante + furnizori) ──

CREATE TABLE seap.entities (
  entity_id     INTEGER PRIMARY KEY,
  entity_type   TEXT NOT NULL CHECK (entity_type IN ('authority', 'supplier')),
  fiscal_number TEXT,
  name          TEXT NOT NULL,
  city          TEXT,
  county        TEXT,
  address       TEXT,
  postal_code   TEXT,
  is_utility    BOOLEAN,
  siruta        TEXT REFERENCES public."GisUat"(siruta),
  match_score   REAL,
  fetched_at    TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at    TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX idx_entities_fiscal ON seap.entities(fiscal_number);
CREATE INDEX idx_entities_siruta ON seap.entities(siruta);
CREATE INDEX idx_entities_type   ON seap.entities(entity_type);
CREATE INDEX idx_entities_county ON seap.entities(county);

-- ── Achiziții directe ──

CREATE TABLE seap.direct_acquisitions (
  id                  INTEGER PRIMARY KEY,
  unique_code         TEXT UNIQUE,
  name                TEXT,
  cpv_code            TEXT,
  cpv_name            TEXT,
  publication_date    TIMESTAMPTZ,
  finalization_date   TIMESTAMPTZ,
  estimated_value     NUMERIC(15,2),
  closing_value       NUMERIC(15,2),
  currency            TEXT DEFAULT 'RON',
  state_id            INTEGER,
  state_text          TEXT,
  contract_type_id    INTEGER,
  contract_type_text  TEXT,
  eu_fund_id          INTEGER,
  eu_fund_text        TEXT,
  authority_id        INTEGER REFERENCES seap.entities(entity_id),
  supplier_id         INTEGER REFERENCES seap.entities(entity_id),
  fetched_at          TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX idx_da_authority     ON seap.direct_acquisitions(authority_id);
CREATE INDEX idx_da_supplier      ON seap.direct_acquisitions(supplier_id);
CREATE INDEX idx_da_finalization  ON seap.direct_acquisitions(finalization_date);
CREATE INDEX idx_da_publication   ON seap.direct_acquisitions(publication_date);
CREATE INDEX idx_da_cpv           ON seap.direct_acquisitions(cpv_code);
CREATE INDEX idx_da_value         ON seap.direct_acquisitions(closing_value);

-- ── Licitații publice (contract award notices) ──

CREATE TABLE seap.public_notices (
  id                  INTEGER PRIMARY KEY,
  notice_no           TEXT,
  contract_title      TEXT,
  cpv_code            TEXT,
  cpv_name            TEXT,
  estimated_value     NUMERIC(15,2),
  contract_value      NUMERIC(15,2),
  currency            TEXT DEFAULT 'RON',
  publication_date    TIMESTAMPTZ,
  state_date          TIMESTAMPTZ,
  procedure_type_id   INTEGER,
  procedure_type_text TEXT,
  contract_type_id    INTEGER,
  contract_type_text  TEXT,
  notice_type_id      INTEGER,
  state_id            INTEGER,
  state_text          TEXT,
  authority_id        INTEGER REFERENCES seap.entities(entity_id),
  authority_city      TEXT,
  authority_county    TEXT,
  authority_siruta    TEXT REFERENCES public."GisUat"(siruta),
  has_lots            BOOLEAN DEFAULT false,
  fetched_at          TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX idx_pn_authority ON seap.public_notices(authority_id);
CREATE INDEX idx_pn_date      ON seap.public_notices(publication_date);
CREATE INDEX idx_pn_siruta    ON seap.public_notices(authority_siruta);
CREATE INDEX idx_pn_cpv       ON seap.public_notices(cpv_code);

-- ── Contracte câștigate (din section 5 a licitațiilor) ──

CREATE TABLE seap.notice_contracts (
  id              SERIAL PRIMARY KEY,
  notice_id       INTEGER REFERENCES seap.public_notices(id),
  lot_number      INTEGER,
  lot_title       TEXT,
  contract_value  NUMERIC(15,2),
  currency        TEXT DEFAULT 'RON',
  contract_date   DATE,
  winner_id       INTEGER REFERENCES seap.entities(entity_id),
  winner_name     TEXT,
  winner_fiscal   TEXT,
  winner_city     TEXT,
  winner_county   TEXT,
  winner_siruta   TEXT REFERENCES public."GisUat"(siruta),
  num_offers      INTEGER
);

CREATE INDEX idx_nc_notice       ON seap.notice_contracts(notice_id);
CREATE INDEX idx_nc_winner       ON seap.notice_contracts(winner_id);
CREATE INDEX idx_nc_winner_siruta ON seap.notice_contracts(winner_siruta);

-- ── Matching localități SEAP → SIRUTA ──

CREATE TABLE seap.locality_map (
  seap_city    TEXT NOT NULL,
  seap_county  TEXT NOT NULL,
  siruta       TEXT REFERENCES public."GisUat"(siruta),
  match_type   TEXT,
  confidence   REAL,
  PRIMARY KEY (seap_city, seap_county)
);

-- ── Stare sync scraper ──

CREATE TABLE seap.sync_state (
  source     TEXT PRIMARY KEY,
  last_date  TIMESTAMPTZ,
  last_id    INTEGER,
  status     TEXT,
  updated_at TIMESTAMPTZ DEFAULT now()
);

INSERT INTO seap.sync_state (source, status) VALUES
  ('da', 'pending'),
  ('notices', 'pending');

-- ── Helper: normalize locality names ──

CREATE OR REPLACE FUNCTION seap.normalize_locality(input TEXT)
RETURNS TEXT LANGUAGE sql IMMUTABLE AS $$
  SELECT lower(trim(unaccent(
    regexp_replace(input, '\s+', ' ', 'g')
  )));
$$;

-- ── Materialized view: procurement stats per UAT ──

CREATE MATERIALIZED VIEW seap.uat_procurement_stats AS
SELECT
  u.siruta,
  u.name   AS uat_name,
  u.county,
  COALESCE(da_stats.da_count, 0)        AS da_count,
  COALESCE(da_stats.da_total_value, 0)   AS da_total_value,
  COALESCE(pn_stats.notice_count, 0)     AS notice_count,
  COALESCE(pn_stats.notice_total_value, 0) AS notice_total_value,
  COALESCE(da_stats.da_count, 0) + COALESCE(pn_stats.notice_count, 0) AS total_contracts,
  COALESCE(da_stats.da_total_value, 0) + COALESCE(pn_stats.notice_total_value, 0) AS total_value
FROM public."GisUat" u
LEFT JOIN LATERAL (
  SELECT
    COUNT(*)           AS da_count,
    SUM(da.closing_value) AS da_total_value
  FROM seap.direct_acquisitions da
  JOIN seap.entities e ON e.entity_id = da.authority_id
  WHERE e.siruta = u.siruta
) da_stats ON true
LEFT JOIN LATERAL (
  SELECT
    COUNT(*)                AS notice_count,
    SUM(pn.contract_value)  AS notice_total_value
  FROM seap.public_notices pn
  WHERE pn.authority_siruta = u.siruta
) pn_stats ON true;

CREATE UNIQUE INDEX idx_ups_siruta ON seap.uat_procurement_stats(siruta);

COMMIT;
