// data.jsx — Mock real-estate dataset (실제로는 국토부/네이버/KB API 연동)
// All prices in 만원 (10,000 KRW). 12억 = 120,000.

// 12개월 정도의 가격 추이를 생성하는 헬퍼
function trail(start, monthsBack, vol = 0.012, trend = 0) {
  const arr = [];
  let v = start;
  for (let i = monthsBack; i >= 0; i--) {
    arr.push({ t: monthLabel(-i), v: Math.round(v) });
    const r = (Math.sin(i * 1.3) * 0.5 + Math.cos(i * 0.7) * 0.3) * vol;
    v = v * (1 + r + trend);
  }
  return arr;
}
function monthLabel(offset) {
  const d = new Date(2026, 4 + offset, 1); // May 2026 base
  return ('' + (d.getFullYear() % 100)).padStart(2, '0') + '.' + ('' + (d.getMonth() + 1)).padStart(2, '0');
}
function forecast(last, monthsAhead = 12, drift = 0.005, spread = 0.025) {
  const arr = []; const band = [];
  let v = last;
  for (let i = 1; i <= monthsAhead; i++) {
    v = v * (1 + drift + Math.sin(i * 0.4) * 0.003);
    arr.push({ t: monthLabel(i), v: Math.round(v) });
    const s = spread * Math.sqrt(i / monthsAhead);
    band.push([Math.round(v * (1 - s)), Math.round(v * (1 + s))]);
  }
  return { forecast: arr, band };
}

// 단지 데이터 ─────────────────────────────────────────────
const APTS = [
  {
    id: 'jeongja-ip',
    name: '정자아이파크',
    region: '경기 성남시 분당구',
    dong: '정자동',
    area: '84㎡',
    built: 2003,
    units: 1748,
    currentPrice: 132000, // 13.2억
    priceM1: 130500,
    priceY1: 128000,
    delta1m: 1.15,
    delta1y: 3.12,
    score: 87,
    grade: 'S',
    signal: 'BUY',
    bestBuyMonth: '26.07',
    targetPrice: 128500,
    confidence: 84,
    pir: 18.2,
    jeonseRatio: 52.4,
    school: 'A+',
    transit: 'A',
    redevelopment: 'B',
    tags: ['신분당선', '분당학군', 'GTX-A 호재'],
    history: trail(132000, 23, 0.014, 0.001),
    risks: ['공급 증가 (위례)', '금리 인상 우려'],
    boons: ['GTX-A 개통 임박', '학원가 우수', '리모델링 추진'],
  },
  {
    id: 'gwanggyo-ho',
    name: '광교호반베르디움',
    region: '경기 수원시 영통구',
    dong: '이의동',
    area: '116㎡',
    built: 2016,
    units: 998,
    currentPrice: 145000,
    priceM1: 142800,
    priceY1: 138000,
    delta1m: 1.54,
    delta1y: 5.07,
    score: 82,
    grade: 'A',
    signal: 'BUY',
    bestBuyMonth: '26.06',
    targetPrice: 142000,
    confidence: 79,
    pir: 16.8,
    jeonseRatio: 48.1,
    school: 'A',
    transit: 'B+',
    redevelopment: 'A',
    tags: ['광교중앙역', '수원광교중심', '리모델링'],
    history: trail(145000, 23, 0.013, 0.002),
    risks: ['수도권 외곽 조정 우려'],
    boons: ['신분당선 연장', '아이비리그학원가', '학군 우수'],
  },
  {
    id: 'jamsil-elsa',
    name: '잠실 엘스',
    region: '서울 송파구',
    dong: '잠실동',
    area: '84㎡',
    built: 2008,
    units: 5678,
    currentPrice: 261000,
    priceM1: 263500,
    priceY1: 255000,
    delta1m: -0.95,
    delta1y: 2.35,
    score: 76,
    grade: 'A',
    signal: 'WATCH',
    bestBuyMonth: '26.09',
    targetPrice: 252000,
    confidence: 71,
    pir: 25.6,
    jeonseRatio: 44.2,
    school: 'A+',
    transit: 'A+',
    redevelopment: 'C',
    tags: ['2호선·8호선', '잠실권', '대단지'],
    history: trail(261000, 23, 0.016, 0.0008),
    risks: ['단기 과열', '거래량 둔화'],
    boons: ['교통 호재', '복합환승센터'],
  },
  {
    id: 'mapo-rmp',
    name: '마포래미안푸르지오',
    region: '서울 마포구',
    dong: '아현동',
    area: '84㎡',
    built: 2014,
    units: 3885,
    currentPrice: 198000,
    priceM1: 199500,
    priceY1: 192000,
    delta1m: -0.75,
    delta1y: 3.12,
    score: 79,
    grade: 'A',
    signal: 'ACC',
    bestBuyMonth: '26.08',
    targetPrice: 192000,
    confidence: 75,
    pir: 21.4,
    jeonseRatio: 49.5,
    school: 'B+',
    transit: 'A',
    redevelopment: 'B',
    tags: ['2호선·5호선·공항철도', '도심권', 'GTX-A 환승'],
    history: trail(198000, 23, 0.015, 0.0012),
    risks: ['전세가율 약세'],
    boons: ['업무지구 인접', 'GTX-A 서울역 환승'],
  },
  {
    id: 'eunma',
    name: '대치 은마',
    region: '서울 강남구',
    dong: '대치동',
    area: '76㎡',
    built: 1979,
    units: 4424,
    currentPrice: 248000,
    priceM1: 245000,
    priceY1: 232000,
    delta1m: 1.22,
    delta1y: 6.89,
    score: 91,
    grade: 'S',
    signal: 'BUY',
    bestBuyMonth: '26.06',
    targetPrice: 244000,
    confidence: 86,
    pir: 28.4,
    jeonseRatio: 38.8,
    school: 'S',
    transit: 'A',
    redevelopment: 'S',
    tags: ['3호선·수인분당선', '대치학원가', '재건축 진행'],
    history: trail(248000, 23, 0.018, 0.0028),
    risks: ['재건축 분담금 변수', '단기 차익실현 매물'],
    boons: ['재건축 사업시행계획 통과', '대치 학원가 1순위', 'GTX-C 호재'],
  },
  {
    id: 'hansol',
    name: '한솔마을 5단지',
    region: '경기 성남시 분당구',
    dong: '정자동',
    area: '59㎡',
    built: 1994,
    units: 1156,
    currentPrice: 78000,
    priceM1: 77500,
    priceY1: 73000,
    delta1m: 0.65,
    delta1y: 6.85,
    score: 84,
    grade: 'A',
    signal: 'ACC',
    bestBuyMonth: '26.07',
    targetPrice: 76500,
    confidence: 81,
    pir: 14.5,
    jeonseRatio: 58.2,
    school: 'A',
    transit: 'A',
    redevelopment: 'A+',
    tags: ['수인분당선', '리모델링 추진', '소형 평형'],
    history: trail(78000, 23, 0.014, 0.0024),
    risks: ['소형 평형 한정 수요'],
    boons: ['리모델링 안전진단 통과', '신분당선 정자역 도보'],
  },
];

// 모델 인사이트용 요인 데이터
const FACTORS = [
  { id: 'transactions', label: '실거래가 추이', sub: '국토부 RTMS · 6개월 MA', value: 18.4, impact: 'positive', source: '국토교통부 실거래가 공개시스템' },
  { id: 'supply', label: '공급 물량', sub: '입주 예정 -32%', value: 14.2, impact: 'positive', source: '한국부동산원 주택공급통계' },
  { id: 'rates', label: '기준금리 / 대출 규제', sub: '한은 동결 + DSR 완화 기대', value: 11.8, impact: 'positive', source: '한국은행 통화정책방향' },
  { id: 'transit', label: '교통 호재', sub: 'GTX-A·C 진척률 87%', value: 9.6, impact: 'positive', source: '국토부 광역교통망 계획' },
  { id: 'school', label: '학군 / 학원가', sub: '대치동·분당·목동 강세', value: 8.1, impact: 'positive', source: '교육통계 + 학원 밀집도' },
  { id: 'redev', label: '재건축 / 재개발', sub: '안전진단·사업시행 단계', value: 7.4, impact: 'positive', source: 'KB부동산 정비사업 DB' },
  { id: 'pir', label: 'PIR (소득 대비)', sub: '서울 28.4 (역사적 고점)', value: 7.0, impact: 'negative', source: 'KB부동산 PIR 지표' },
  { id: 'macro', label: '거시 경제 (GDP·CPI)', sub: 'GDP +2.1%, CPI 2.4%', value: 6.2, impact: 'positive', source: '통계청 경제지표' },
  { id: 'volume', label: '거래량 / 매물 수', sub: '거래 +24% MoM', value: 5.7, impact: 'positive', source: '국토부 거래량' },
  { id: 'jeonse', label: '전세가율', sub: '54.2% (10년 평균)', value: 4.8, impact: 'positive', source: 'KB 주택가격동향' },
  { id: 'income', label: '지역별 소득 수준', sub: '강남 3구 +6.4% YoY', value: 3.5, impact: 'positive', source: '국세청 통합소득' },
  { id: 'pop', label: '인구 이동 / 청약', sub: '경쟁률 평균 18:1', value: 3.3, impact: 'positive', source: '청약홈 + 통계청' },
];

// 리포트 / 논문 인용
const REPORTS = [
  { type: 'paper', title: '주택가격 결정요인의 시계열 분석 (Park & Kim, 2024)', org: '한국부동산학회', date: '2024.11' },
  { type: 'report', title: '주택시장 전망 - 2026 상반기', org: '한국부동산원', date: '2026.04' },
  { type: 'report', title: 'KB 부동산시장 리뷰', org: 'KB경영연구소', date: '2026.05' },
  { type: 'paper', title: 'GTX 노선 효과 - 인접 단지 프리미엄', org: 'KDI', date: '2025.09' },
  { type: 'data',  title: '실거래가 공개시스템', org: '국토교통부 RTMS', date: 'realtime' },
  { type: 'paper', title: '학군 프리미엄의 헤도닉 가격 분석', org: '주택연구', date: '2025.06' },
];

// 사이드 알림용 뉴스
const NEWS = [
  { tag: '호재', region: '성남시 분당구', title: 'GTX-A 성남역 6월 부분 개통 확정', source: '연합뉴스', time: '12분 전', impact: 'positive' },
  { tag: '정책', region: '서울 전역', title: 'DSR 규제 일부 완화 검토 - 6월 중 발표', source: '머니투데이', time: '38분 전', impact: 'positive' },
  { tag: '공급', region: '서울 강동구', title: '둔촌주공 입주 임박 - 인근 시세 조정 압력', source: '한국경제', time: '1시간 전', impact: 'negative' },
  { tag: '재건축', region: '서울 강남구', title: '대치 은마 사업시행계획 변경안 가결', source: '매일경제', time: '2시간 전', impact: 'positive' },
  { tag: '학군', region: '서울 양천구', title: '목동신시가지 학원가 확장 영향 분석', source: 'KB리포트', time: '3시간 전', impact: 'positive' },
];

// 티커용 시세
const TICKERS = [
  { code: 'KB.APT', label: '전국 아파트', price: 5128, delta: 0.42 },
  { code: 'SEL.GN', label: '강남구', price: 26840, delta: 0.86 },
  { code: 'SEL.SP', label: '송파구', price: 21450, delta: -0.21 },
  { code: 'SEL.MP', label: '마포구', price: 14820, delta: 0.34 },
  { code: 'GG.BD',  label: '분당구', price: 12640, delta: 0.71 },
  { code: 'GG.SW',  label: '수원영통', price: 9280, delta: 0.55 },
  { code: 'BoK',    label: '기준금리 2.75%', price: 275, delta: 0 },
  { code: 'CPI',    label: 'CPI YoY', price: 24, delta: -0.10 },
];

// 지역별 비교
const REGIONS = [
  { name: '강남구',   score: 88, delta1y: 6.4, pir: 28.4, jeonse: 38.8, signal: 'BUY',   trend: trail(180, 12, 0.013, 0.003).map(d => d.v) },
  { name: '서초구',   score: 85, delta1y: 5.9, pir: 27.1, jeonse: 40.2, signal: 'BUY',   trend: trail(175, 12, 0.013, 0.0028).map(d => d.v) },
  { name: '송파구',   score: 76, delta1y: 2.35, pir: 25.6, jeonse: 44.2, signal: 'WATCH', trend: trail(155, 12, 0.014, 0.0009).map(d => d.v) },
  { name: '분당구',   score: 84, delta1y: 4.7, pir: 18.2, jeonse: 52.4, signal: 'BUY',   trend: trail(130, 12, 0.012, 0.0021).map(d => d.v) },
  { name: '마포구',   step: 79, score: 79, delta1y: 3.12, pir: 21.4, jeonse: 49.5, signal: 'ACC', trend: trail(140, 12, 0.012, 0.0016).map(d => d.v) },
  { name: '수원영통', score: 82, delta1y: 5.07, pir: 16.8, jeonse: 48.1, signal: 'BUY',   trend: trail(110, 12, 0.013, 0.0024).map(d => d.v) },
  { name: '용산구',   score: 80, delta1y: 4.1, pir: 24.0, jeonse: 43.0, signal: 'ACC',   trend: trail(165, 12, 0.013, 0.0020).map(d => d.v) },
  { name: '광진구',   score: 71, delta1y: 1.8, pir: 22.2, jeonse: 47.6, signal: 'HOLD',  trend: trail(125, 12, 0.012, 0.0008).map(d => d.v) },
];

// ─────────────────────────────────────────────────────────
// 단지 데이터 대규모 생성 — 전국 주요 지역 약 180개 단지
// 실제 RTMS 와 비슷한 분포 (강남·송파·분당 비쌈, 지방·외곽 저렴)
// ─────────────────────────────────────────────────────────
const BRANDS = ['아이파크', '래미안', '푸르지오', '자이', 'e편한세상', '롯데캐슬', '더샵',
  '힐스테이트', '호반베르디움', '센트럴파크', '리버뷰', '리버파크', '에듀포레', '센트레빌',
  '데시앙', '두산위브', 'SK뷰', '한신더휴', '리젠시', '캐슬'];
const REGION_DEFS = [
  // [region, dong, basePrice(만), priceVol%, score range]
  ['서울 강남구', '대치동',   240000, 1.5, [82, 95]],
  ['서울 강남구', '도곡동',   235000, 1.3, [80, 92]],
  ['서울 강남구', '개포동',   220000, 1.6, [78, 90]],
  ['서울 강남구', '역삼동',   215000, 1.2, [75, 88]],
  ['서울 강남구', '청담동',   260000, 1.4, [80, 94]],
  ['서울 강남구', '논현동',   200000, 1.2, [72, 85]],
  ['서울 강남구', '삼성동',   245000, 1.3, [78, 91]],
  ['서울 서초구', '반포동',   270000, 1.5, [83, 95]],
  ['서울 서초구', '잠원동',   235000, 1.3, [78, 90]],
  ['서울 서초구', '서초동',   210000, 1.2, [75, 88]],
  ['서울 서초구', '방배동',   195000, 1.1, [72, 85]],
  ['서울 송파구', '잠실동',   255000, 1.4, [76, 89]],
  ['서울 송파구', '신천동',   220000, 1.3, [74, 86]],
  ['서울 송파구', '가락동',   180000, 1.2, [70, 84]],
  ['서울 송파구', '문정동',   165000, 1.1, [68, 82]],
  ['서울 강동구', '고덕동',   145000, 1.3, [72, 85]],
  ['서울 강동구', '둔촌동',   135000, 1.4, [70, 84]],
  ['서울 강동구', '천호동',   125000, 1.0, [65, 78]],
  ['서울 마포구', '아현동',   195000, 1.3, [78, 90]],
  ['서울 마포구', '공덕동',   180000, 1.2, [75, 86]],
  ['서울 마포구', '대흥동',   170000, 1.2, [73, 85]],
  ['서울 마포구', '상암동',   160000, 1.1, [70, 82]],
  ['서울 용산구', '한남동',   320000, 1.5, [85, 96]],
  ['서울 용산구', '이촌동',   250000, 1.3, [80, 92]],
  ['서울 용산구', '동부이촌동', 230000, 1.3, [78, 90]],
  ['서울 성동구', '성수동',   210000, 1.4, [78, 91]],
  ['서울 성동구', '옥수동',   190000, 1.3, [76, 88]],
  ['서울 성동구', '왕십리',   175000, 1.2, [73, 85]],
  ['서울 광진구', '광장동',   175000, 1.2, [72, 85]],
  ['서울 광진구', '자양동',   145000, 1.1, [68, 80]],
  ['서울 종로구', '평창동',   220000, 1.1, [72, 84]],
  ['서울 중구',   '신당동',   165000, 1.1, [70, 82]],
  ['서울 영등포구', '여의도동', 240000, 1.3, [78, 90]],
  ['서울 영등포구', '당산동',  140000, 1.1, [68, 80]],
  ['서울 영등포구', '문래동',  155000, 1.1, [70, 82]],
  ['서울 양천구', '목동',     180000, 1.3, [78, 90]],
  ['서울 양천구', '신정동',   145000, 1.1, [70, 82]],
  ['서울 강서구', '마곡동',   165000, 1.3, [74, 86]],
  ['서울 강서구', '화곡동',   115000, 1.0, [62, 75]],
  ['서울 동작구', '흑석동',   175000, 1.3, [75, 87]],
  ['서울 동작구', '사당동',   155000, 1.1, [70, 82]],
  ['서울 동작구', '상도동',   135000, 1.1, [68, 80]],
  ['서울 관악구', '봉천동',   115000, 1.0, [60, 73]],
  ['서울 관악구', '신림동',   105000, 1.0, [58, 70]],
  ['서울 노원구', '상계동',   95000,  1.0, [60, 72]],
  ['서울 노원구', '중계동',   115000, 1.1, [66, 78]],
  ['서울 도봉구', '창동',     100000, 1.0, [60, 72]],
  ['서울 성북구', '길음동',   135000, 1.1, [70, 82]],
  ['서울 성북구', '장위동',   115000, 1.0, [65, 77]],
  ['서울 서대문구', '북아현동', 165000, 1.2, [72, 84]],
  ['서울 서대문구', '홍은동',  110000, 1.0, [62, 74]],
  ['서울 은평구', '응암동',   115000, 1.0, [65, 76]],
  ['서울 은평구', '진관동',   135000, 1.1, [70, 82]],
  ['서울 중랑구', '면목동',   95000,  1.0, [58, 70]],
  ['서울 동대문구', '전농동', 120000, 1.1, [68, 80]],
  ['서울 강북구', '미아동',   95000,  0.9, [58, 70]],
  ['서울 구로구', '신도림동', 145000, 1.1, [70, 82]],
  ['서울 금천구', '독산동',   105000, 0.9, [60, 72]],

  // 경기 — 분당/판교/광교/일산/평촌 등
  ['경기 성남시 분당구', '정자동',    135000, 1.2, [78, 90]],
  ['경기 성남시 분당구', '서현동',    140000, 1.2, [76, 88]],
  ['경기 성남시 분당구', '수내동',    145000, 1.2, [78, 90]],
  ['경기 성남시 분당구', '백현동',    220000, 1.4, [83, 94]],  // 판교
  ['경기 성남시 분당구', '삼평동',    195000, 1.3, [80, 92]],
  ['경기 수원시 영통구', '이의동',    140000, 1.3, [80, 92]], // 광교
  ['경기 수원시 영통구', '원천동',    125000, 1.2, [75, 87]],
  ['경기 수원시 영통구', '망포동',    95000,  1.1, [70, 82]],
  ['경기 수원시 영통구', '영통동',    110000, 1.1, [70, 82]],
  ['경기 수원시 권선구', '권선동',    85000,  1.0, [62, 74]],
  ['경기 수원시 장안구', '정자동',    95000,  1.0, [65, 77]],
  ['경기 수원시 팔달구', '인계동',    105000, 1.1, [68, 80]],
  ['경기 고양시 일산서구', '주엽동',  95000,  1.0, [62, 74]],
  ['경기 고양시 일산서구', '대화동',  85000,  1.0, [60, 72]],
  ['경기 고양시 일산동구', '백석동',  90000,  1.0, [62, 74]],
  ['경기 고양시 덕양구',   '행신동',  85000,  1.0, [60, 72]],
  ['경기 안양시 동안구',   '평촌동',  125000, 1.2, [72, 84]],
  ['경기 안양시 동안구',   '범계동',  120000, 1.2, [70, 82]],
  ['경기 안양시 만안구',   '안양동',  90000,  1.0, [62, 74]],
  ['경기 용인시 수지구',   '죽전동',  115000, 1.2, [70, 82]],
  ['경기 용인시 수지구',   '풍덕천동', 105000, 1.1, [68, 80]],
  ['경기 용인시 기흥구',   '구갈동',  85000,  1.0, [62, 74]],
  ['경기 용인시 기흥구',   '동백동',  95000,  1.0, [65, 77]],
  ['경기 용인시 처인구',   '김량장동', 70000, 0.9, [55, 67]],
  ['경기 화성시',         '동탄동',  115000, 1.3, [72, 84]],
  ['경기 화성시',         '능동',    105000, 1.2, [68, 80]],
  ['경기 화성시',         '봉담읍',  75000,  1.0, [60, 72]],
  ['경기 평택시',         '비전동',  75000,  1.0, [60, 72]],
  ['경기 평택시',         '고덕면',  85000,  1.1, [65, 77]],
  ['경기 김포시',         '운양동',  85000,  1.1, [65, 77]],
  ['경기 김포시',         '장기동',  80000,  1.0, [62, 74]],
  ['경기 광명시',         '철산동',  125000, 1.2, [72, 84]],
  ['경기 광명시',         '하안동',  105000, 1.1, [68, 80]],
  ['경기 부천시',         '중동',    105000, 1.1, [68, 80]],
  ['경기 부천시',         '상동',    115000, 1.1, [70, 82]],
  ['경기 부천시',         '소사동',  85000,  1.0, [62, 74]],
  ['경기 안산시 단원구',   '고잔동',  85000,  1.0, [62, 74]],
  ['경기 안산시 상록구',   '본오동',  75000,  0.9, [58, 70]],
  ['경기 시흥시',         '정왕동',  75000,  1.0, [58, 70]],
  ['경기 시흥시',         '배곧동',  95000,  1.1, [65, 77]],
  ['경기 의왕시',         '오전동',  95000,  1.0, [65, 77]],
  ['경기 의정부시',       '민락동',  85000,  1.0, [62, 74]],
  ['경기 남양주시',       '다산동',  115000, 1.2, [70, 82]],
  ['경기 남양주시',       '별내동',  95000,  1.1, [65, 77]],
  ['경기 구리시',         '인창동',  95000,  1.0, [65, 77]],
  ['경기 하남시',         '미사동',  135000, 1.3, [74, 86]],
  ['경기 하남시',         '망월동',  115000, 1.2, [70, 82]],
  ['경기 양평군',         '양평읍',  55000,  0.8, [50, 62]],
  ['경기 파주시',         '운정동',  85000,  1.0, [62, 74]],

  // 인천
  ['인천 연수구',         '송도동',  165000, 1.4, [76, 88]],
  ['인천 연수구',         '연수동',  85000,  1.0, [62, 74]],
  ['인천 서구',           '청라동',  125000, 1.2, [70, 82]],
  ['인천 서구',           '검단동',  85000,  1.0, [62, 74]],
  ['인천 남동구',         '구월동',  85000,  1.0, [62, 74]],
  ['인천 부평구',         '부평동',  75000,  0.9, [58, 70]],
  ['인천 계양구',         '계산동',  75000,  0.9, [58, 70]],
  ['인천 미추홀구',       '주안동',  70000,  0.9, [55, 67]],

  // 부산
  ['부산 해운대구',       '우동',    140000, 1.3, [76, 88]],
  ['부산 해운대구',       '중동',    155000, 1.4, [78, 90]],
  ['부산 해운대구',       '재송동',  105000, 1.1, [68, 80]],
  ['부산 수영구',         '광안동',  115000, 1.2, [70, 82]],
  ['부산 수영구',         '남천동',  135000, 1.3, [74, 86]],
  ['부산 동래구',         '명륜동',  95000,  1.0, [65, 77]],
  ['부산 남구',           '대연동',  85000,  1.0, [62, 74]],
  ['부산 사하구',         '괴정동',  65000,  0.8, [55, 67]],
  ['부산 부산진구',       '전포동',  85000,  1.0, [62, 74]],
  ['부산 연제구',         '연산동',  85000,  1.0, [62, 74]],

  // 대구
  ['대구 수성구',         '범어동',  165000, 1.3, [76, 88]],
  ['대구 수성구',         '두산동',  125000, 1.2, [72, 84]],
  ['대구 중구',           '대봉동',  85000,  1.0, [62, 74]],
  ['대구 달서구',         '월성동',  85000,  1.0, [62, 74]],
  ['대구 북구',           '침산동',  75000,  0.9, [58, 70]],

  // 대전
  ['대전 유성구',         '도룡동',  125000, 1.2, [72, 84]],
  ['대전 유성구',         '봉명동',  95000,  1.0, [65, 77]],
  ['대전 서구',           '둔산동',  115000, 1.2, [70, 82]],
  ['대전 서구',           '도안동',  95000,  1.0, [65, 77]],
  ['대전 중구',           '문화동',  75000,  0.9, [58, 70]],

  // 광주
  ['광주 남구',           '봉선동',  95000,  1.0, [65, 77]],
  ['광주 서구',           '풍암동',  85000,  1.0, [62, 74]],
  ['광주 광산구',         '수완동',  75000,  0.9, [58, 70]],

  // 울산·세종
  ['울산 남구',           '신정동',  95000,  1.0, [65, 77]],
  ['울산 중구',           '병영동',  75000,  0.9, [58, 70]],
  ['세종특별자치시',       '도담동',  105000, 1.2, [70, 82]],
  ['세종특별자치시',       '새롬동',  115000, 1.2, [72, 84]],
  ['세종특별자치시',       '한솔동',  85000,  1.0, [62, 74]],

  // 강원
  ['강원 춘천시',         '석사동',  55000,  0.8, [50, 62]],
  ['강원 원주시',         '단계동',  55000,  0.8, [50, 62]],
  ['강원 강릉시',         '교동',    65000,  0.9, [55, 67]],
];

// 시그널 결정 헬퍼
function decideSignal(score, delta1y) {
  if (score >= 85 && delta1y < 8) return 'BUY';
  if (score >= 78) return 'ACC';
  if (score >= 65) return 'WATCH';
  if (score >= 55) return 'HOLD';
  return 'AVOID';
}
function decideGrade(score) {
  return score >= 85 ? 'S' : score >= 72 ? 'A' : score >= 60 ? 'B' : 'C';
}
function decideBestMonth(score) {
  // 점수 높을수록 가까운 미래
  const m = score >= 85 ? 1 : score >= 75 ? 2 : score >= 65 ? 4 : 6;
  const d = new Date(2026, 4 + m);
  return ('' + (d.getFullYear() % 100)).padStart(2, '0') + '.' + ('' + (d.getMonth() + 1)).padStart(2, '0');
}

// pseudo-random 결정적 — id 기반
function prng(seed) {
  let h = 0;
  for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) | 0;
  return () => {
    h = (h * 1103515245 + 12345) & 0x7fffffff;
    return (h % 10000) / 10000;
  };
}

function genApts() {
  const out = [];
  // 기존 6개 유지
  out.push(...APTS);
  const existingNames = new Set(APTS.map(a => a.name));

  REGION_DEFS.forEach((def, regionIdx) => {
    const [region, dong, basePrice, vol, scoreRange] = def;
    // 단지 1~3개 생성
    const r0 = prng(region + dong);
    const count = 1 + Math.floor(r0() * 3); // 1~3
    for (let i = 0; i < count; i++) {
      const r = prng(region + dong + i);
      const brand = BRANDS[Math.floor(r() * BRANDS.length)];
      const phaseNum = Math.floor(r() * 4);
      const phaseTxt = phaseNum > 0 ? ' ' + (phaseNum + 1) + '단지' : '';
      const name = dong.replace(/동$|읍$|면$/, '') + brand + phaseTxt;
      if (existingNames.has(name)) continue;
      existingNames.add(name);

      const priceJitter = 1 + (r() - 0.5) * 0.4; // ±20%
      const price = Math.round(basePrice * priceJitter / 1000) * 1000;
      const score = Math.round(scoreRange[0] + r() * (scoreRange[1] - scoreRange[0]));
      const delta1y = ((r() - 0.3) * 14).toFixed(2);
      const delta1m = ((r() - 0.45) * 3).toFixed(2);
      const built = 1985 + Math.floor(r() * 39);
      const units = 200 + Math.floor(r() * 4000);
      const area = (() => {
        const a = ['59㎡', '74㎡', '84㎡', '99㎡', '114㎡', '134㎡'];
        return a[Math.floor(r() * a.length)];
      })();
      const pir = 12 + r() * 18;
      const jeonse = 38 + r() * 25;
      const targetPrice = Math.round(price * (0.94 + r() * 0.04) / 100) * 100;
      const confidence = 65 + Math.floor(r() * 28);
      const signal = decideSignal(score, parseFloat(delta1y));
      const grade = decideGrade(score);

      // 태그
      const subwayTags = ['신분당선', '2호선', '9호선', '3호선', '수인분당선', 'GTX-A', 'GTX-C',
        '5호선', '7호선', '경의중앙선', '신림선', '공항철도'];
      const featTags = ['학군 우수', '재건축 추진', '리모델링', '한강뷰', '대단지', '역세권', '신축', '학원가'];
      const tags = [];
      tags.push(subwayTags[Math.floor(r() * subwayTags.length)]);
      tags.push(featTags[Math.floor(r() * featTags.length)]);
      if (r() > 0.6) tags.push(featTags[Math.floor(r() * featTags.length)]);

      out.push({
        id: 'apt-' + regionIdx + '-' + i,
        name,
        region, dong, area, built, units,
        currentPrice: price,
        priceM1: Math.round(price * (1 - parseFloat(delta1m) / 100)),
        priceY1: Math.round(price * (1 - parseFloat(delta1y) / 100)),
        delta1m: parseFloat(delta1m),
        delta1y: parseFloat(delta1y),
        score, grade, signal,
        bestBuyMonth: decideBestMonth(score),
        targetPrice,
        confidence,
        pir: parseFloat(pir.toFixed(1)),
        jeonseRatio: parseFloat(jeonse.toFixed(1)),
        school: ['S', 'A+', 'A', 'B+', 'B', 'C'][Math.floor(r() * 6)],
        transit: ['A+', 'A', 'B+', 'B', 'C'][Math.floor(r() * 5)],
        redevelopment: ['S', 'A', 'B', 'C', '-'][Math.floor(r() * 5)],
        tags: [...new Set(tags)],
        history: trail(price, 23, vol / 100, (Math.random() - 0.3) * 0.003),
        risks: ['공급 증가 우려', '금리 인상 영향', '거래량 둔화', '단기 과열'][Math.floor(r() * 4)].split('|').slice(0, 2),
        boons: ['교통 호재', '학군 강세', '리모델링 추진', '신축 분양', '도시정비계획'][Math.floor(r() * 5)].split('|').slice(0, 2),
      });
    }
  });
  return out;
}

// 기존 APTS 를 덮어쓰기
const ALL_APTS = genApts();
// APTS 변수 자체를 확장된 데이터로 교체
APTS.length = 0;
ALL_APTS.forEach(a => APTS.push(a));

Object.assign(window, { APTS, FACTORS, REPORTS, NEWS, TICKERS, REGIONS, trail, forecast });
