-- Per-location padel investment opportunity intelligence.
-- Consumed by: Gemeinde-level pSEO pages, opportunity map, "top markets" lists.
--
-- Padelnomics Marktpotenzial-Score v2 (0–100):
-- Answers "Where should I build a padel court?"
-- Covers ALL GeoNames locations (pop ≥ 1K) — NOT filtered to existing padel markets.
-- Zero-court locations score highest on supply gap component (white space = opportunity).
--
--   25 pts  addressable market — log-scaled population, ceiling 500K
--           (opportunity peaks in mid-size cities; megacities already served)
--   20 pts  economic power     — country income PPS, normalised to 35,000
--                               EU PPS values range 18k-37k; /35k gives real spread.
--                               DE ≈ 13.2pts, ES ≈ 10.7pts, SE ≈ 14.3pts.
--                               Previously /200 caused all countries to saturate at 20/20.
--   30 pts  supply gap         — INVERTED venue density; 0 courts/100K = full marks.
--                               Ceiling raised to 8/100K (was 4) for a gentler gradient
--                               and to account for ~87% data undercount vs FIP totals.
--                               Linear: GREATEST(0, 1 - density/8)
--   15 pts  catchment gap      — distance to nearest padel court.
--                               DuckDB LEAST ignores NULLs: LEAST(1.0, NULL/30) = 1.0,
--                               so NULL nearest_km = full marks (no court in bounding box
--                               = high opportunity). COALESCE fallback is dead code.
--   10 pts  sports culture     — tennis courts within 25km (≥10 = full marks).
--                               NOTE: dim_locations tennis data is empty (all 0 rows).
--                               Component contributes 0 pts everywhere until data lands.

MODEL (
  name serving.location_opportunity_profile,
  kind FULL,
  cron '@daily',
  grain (country_code, geoname_id)
);

SELECT
  l.geoname_id,
  l.country_code,
  l.country_name_en,
  l.country_slug,
  l.location_name,
  l.location_slug,
  l.lat,
  l.lon,
  l.admin1_code,
  l.admin2_code,
  l.population,
  l.population_year,
  l.median_income_pps,
  l.income_year,
  l.padel_venue_count,
  l.padel_venues_per_100k,
  l.nearest_padel_court_km,
  l.tennis_courts_within_25km,
  ROUND(
    -- Addressable market (25 pts): log-scaled to 500K ceiling.
    -- Lower ceiling than Marktreife (1M) — opportunity peaks in mid-size cities
    -- that can support a court but aren't already saturated by large-city operators.
    25.0 * LEAST(1.0, LN(GREATEST(l.population, 1)) / LN(500000))

    -- Economic power (20 pts): country-level income PPS normalised to 35,000.
    -- Drives willingness-to-pay for court fees (€20-35/hr target range).
    -- EU PPS values range 18k-37k; ceiling 35k gives meaningful spread.
    -- v1 used /200 which caused LEAST(1.0, 115) = 1.0 for ALL countries (flat, no differentiation).
    -- v2: /35000 → DE 0.66×20=13.2pts, ES 0.53×20=10.7pts, SE 0.71×20=14.3pts.
    -- Default 15000 for missing data = reasonable developing-market assumption (~0.43).
    + 20.0 * LEAST(1.0, COALESCE(l.median_income_pps, 15000) / 35000.0)

    -- Supply gap (30 pts): INVERTED venue density.
    -- 0 courts/100K = full 30 pts (white space); ≥8/100K = 0 pts (served market).
    -- Ceiling raised from 4→8/100K for a gentler gradient and to account for data
    -- undercount (~87% of real courts not in our data).
    -- This is the key signal that separates Marktpotenzial from Marktreife.
    + 30.0 * GREATEST(0.0, 1.0 - COALESCE(l.padel_venues_per_100k, 0) / 8.0)

    -- Catchment gap (15 pts): distance to nearest existing padel court.
    -- >30km = full 15 pts (underserved catchment area).
    -- NULL = no courts found anywhere (rare edge case) → neutral 0.5.
    + 15.0 * COALESCE(LEAST(1.0, l.nearest_padel_court_km / 30.0), 0.5)

    -- Sports culture proxy (10 pts): tennis courts within 25km.
    -- ≥10 courts = full 10 pts (proven racket sport market = faster padel adoption).
    -- 0 courts = 0 pts. Many new padel courts open inside existing tennis clubs.
    + 10.0 * LEAST(1.0, l.tennis_courts_within_25km / 10.0)
  , 1)                                                                   AS opportunity_score,
  CURRENT_DATE                                                           AS refreshed_date
FROM foundation.dim_locations l
ORDER BY opportunity_score DESC
