// UR租房助手 — data, API client, icons

const { useState, useEffect, useRef, useMemo } = React;

// ─────────────────────────────────────────────────────────────
// API client
// ─────────────────────────────────────────────────────────────
const API_BASE = 'https://api.repilot.jp';
const API_TOKEN = '71d7f127d638d19071af0fb6caaa4e53a8e20d4c39161aa5';
const SUBSCRIBE_API_BASE = (() => {
  const host = window.location.hostname;
  if (host === '127.0.0.1' || host === 'localhost') return 'http://127.0.0.1:4175';
  return '';
})();
const WATCH_SESSION_STORAGE_KEY = 'ur_watch_session_v1';

async function apiFetch(path) {
  const res = await fetch(API_BASE + path, {
    headers: { Authorization: 'Bearer ' + API_TOKEN },
  });
  if (!res.ok) throw new Error('API ' + res.status);
  return res.json();
}

async function subscribeApiFetch(path, options = {}) {
  const res = await fetch(SUBSCRIBE_API_BASE + '/api/subscriptions' + path, {
    method: options.method || 'GET',
    headers: {
      ...(options.body ? { 'Content-Type': 'application/json' } : {}),
      ...(options.token ? { Authorization: 'Bearer ' + options.token } : {}),
      ...(options.headers || {}),
    },
    body: options.body ? JSON.stringify(options.body) : undefined,
  });

  const text = await res.text();
  const data = text ? JSON.parse(text) : null;
  if (!res.ok) throw new Error(data?.error || 'SUBSCRIBE_API_' + res.status);
  return data;
}

function getWatchSession() {
  try {
    const raw = localStorage.getItem(WATCH_SESSION_STORAGE_KEY);
    return raw ? JSON.parse(raw) : null;
  } catch (error) {
    return null;
  }
}

function setWatchSession(session) {
  localStorage.setItem(WATCH_SESSION_STORAGE_KEY, JSON.stringify(session));
}

function clearWatchSession() {
  localStorage.removeItem(WATCH_SESSION_STORAGE_KEY);
}

function formatDateTimeZh(value) {
  if (!value) return '—';
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return new Intl.DateTimeFormat('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  }).format(date);
}

function normalizeDistrictName(value) {
  return String(value || '').trim();
}

function splitAreaRange(range) {
  return String(range || '')
    .split(/[、,，]/)
    .map((item) => item.trim())
    .filter(Boolean);
}

function buildDistrictOptions(items, selectedAreaKeys, areasByRegion, getDistrictName) {
  const areaSet = new Set(selectedAreaKeys || []);
  const preferredOrder = new Map();
  let nextOrder = 0;

  for (const areaKey of selectedAreaKeys || []) {
    const regionKey = String(areaKey).split('__')[0];
    const area = areasByRegion?.[regionKey]?.data?.find((item) => item.areaKey === areaKey);
    for (const district of splitAreaRange(area?.range)) {
      const normalized = normalizeDistrictName(district);
      if (!normalized || preferredOrder.has(normalized)) continue;
      preferredOrder.set(normalized, nextOrder++);
    }
  }

  const grouped = new Map();
  for (const item of items || []) {
    if (areaSet.size > 0 && !areaSet.has(item.areaKey)) continue;
    const district = normalizeDistrictName(getDistrictName(item));
    if (!district) continue;
    const current = grouped.get(district) || {
      key: district,
      label: district,
      propertyCount: 0,
      roomCount: 0,
    };
    current.propertyCount += 1;
    current.roomCount += item.activeRoomCount ?? item.roomCount ?? (item.rooms || []).length ?? 0;
    grouped.set(district, current);
  }

  return Array.from(grouped.values()).sort((a, b) => {
    const orderA = preferredOrder.has(a.key) ? preferredOrder.get(a.key) : Number.MAX_SAFE_INTEGER;
    const orderB = preferredOrder.has(b.key) ? preferredOrder.get(b.key) : Number.MAX_SAFE_INTEGER;
    if (orderA !== orderB) return orderA - orderB;
    return a.label.localeCompare(b.label, 'ja');
  });
}

// ─────────────────────────────────────────────────────────────
// Region groupings (UR's fixed mapping, adapted for mobile)
// Maps Chinese/Japanese display labels to regionKey used by API.
// ─────────────────────────────────────────────────────────────
const REGIONS = [
  { name: '北海道・東北', prefs: [
    { label: '北海道', key: 'hokkaido' },
    { label: '宮城県', key: 'miyagi' },
  ]},
  { name: '関東', prefs: [
    { label: '東京都', key: 'tokyo' },
    { label: '神奈川県', key: 'kanagawa' },
    { label: '千葉県', key: 'chiba' },
    { label: '埼玉県', key: 'saitama' },
    { label: '茨城県', key: 'ibaraki' },
  ]},
  { name: '東海', prefs: [
    { label: '愛知県', key: 'aichi' },
    { label: '三重県', key: 'mie' },
    { label: '岐阜県', key: 'gifu' },
  ]},
  { name: '関西', prefs: [
    { label: '大阪府', key: 'osaka' },
    { label: '兵庫県', key: 'hyogo' },
    { label: '京都府', key: 'kyoto' },
    { label: '滋賀県', key: 'shiga' },
    { label: '奈良県', key: 'nara' },
    { label: '和歌山県', key: 'wakayama' },
  ]},
  { name: '中国', prefs: [
    { label: '岡山県', key: 'okayama' },
    { label: '広島県', key: 'hiroshima' },
    { label: '山口県', key: 'yamaguchi' },
  ]},
  { name: '九州', prefs: [
    { label: '福岡県', key: 'fukuoka' },
  ]},
];

// ─────────────────────────────────────────────────────────────
// Rent parsing: "44,000円～51,200円" → { min, max }
// ─────────────────────────────────────────────────────────────
function parseRentRange(s) {
  if (!s) return { min: 0, max: 0 };
  const nums = s.replace(/,/g, '').match(/\d+/g);
  if (!nums) return { min: 0, max: 0 };
  const ns = nums.map(n => parseInt(n, 10));
  return { min: ns[0], max: ns[ns.length - 1] };
}

// "万円" formatting
const manYen = (n) => {
  if (!n) return '0';
  if (n >= 10000) {
    const man = n / 10000;
    return man % 1 === 0 ? `${man}万` : `${man.toFixed(1)}万`;
  }
  return n.toLocaleString('ja-JP');
};

// Resolve image URL (prefer local hosted asset if relative)
function resolveImg(url) {
  if (!url) return null;
  if (url.startsWith('/')) return API_BASE + url;
  return url;
}

// ─────────────────────────────────────────────────────────────
// Icons
// ─────────────────────────────────────────────────────────────
const Icon = {
  Chevron: ({ size = 14, dir = 'down', color = 'currentColor' }) => (
    <svg width={size} height={size} viewBox="0 0 16 16" style={{
      transform: { down: 'rotate(0deg)', up: 'rotate(180deg)', right: 'rotate(-90deg)', left: 'rotate(90deg)' }[dir],
      transition: 'transform 180ms ease',
    }}>
      <path d="M3 6l5 5 5-5" stroke={color} strokeWidth="1.6" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  ),
  Close: ({ size = 18, color = 'currentColor' }) => (
    <svg width={size} height={size} viewBox="0 0 20 20">
      <path d="M5 5l10 10M15 5L5 15" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
    </svg>
  ),
  Location: ({ size = 14, color = 'currentColor' }) => (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none">
      <path d="M8 14s5-4.5 5-8a5 5 0 10-10 0c0 3.5 5 8 5 8z" stroke={color} strokeWidth="1.3"/>
      <circle cx="8" cy="6" r="1.8" stroke={color} strokeWidth="1.3"/>
    </svg>
  ),
  Yen: ({ size = 14, color = 'currentColor' }) => (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none">
      <path d="M4 3l4 5 4-5M4 9h8M4 12h8M8 8v5" stroke={color} strokeWidth="1.3" strokeLinecap="round"/>
    </svg>
  ),
  Home: ({ size = 22, color = 'currentColor', fill = false }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none">
      <path d="M4 10.5L12 4l8 6.5V20a0 0 0 01 0 0H4V10.5z" stroke={color} strokeWidth="1.7" fill={fill ? color : 'none'} strokeLinejoin="round"/>
      <path d="M9.5 20v-6h5v6" stroke={fill ? '#fff' : color} strokeWidth="1.7" fill="none" strokeLinejoin="round"/>
    </svg>
  ),
  Bell: ({ size = 22, color = 'currentColor', fill = false }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none">
      <path d="M6 17h12l-1.5-2V11a4.5 4.5 0 00-9 0v4L6 17z" stroke={color} strokeWidth="1.7" fill={fill ? color : 'none'} strokeLinejoin="round"/>
      <path d="M10 20a2 2 0 004 0" stroke={color} strokeWidth="1.7" strokeLinecap="round"/>
    </svg>
  ),
  Search: ({ size = 16, color = 'currentColor' }) => (
    <svg width={size} height={size} viewBox="0 0 20 20" fill="none">
      <circle cx="9" cy="9" r="5.5" stroke={color} strokeWidth="1.5"/>
      <path d="M13 13l4 4" stroke={color} strokeWidth="1.5" strokeLinecap="round"/>
    </svg>
  ),
  Sort: ({ size = 14, color = 'currentColor' }) => (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none">
      <path d="M4 3v10M4 13l-2-2M4 13l2-2M12 13V3M12 3l-2 2M12 3l2 2" stroke={color} strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  ),
  Refresh: ({ size = 14, color = 'currentColor' }) => (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none">
      <path d="M13 4a5.5 5.5 0 10-1.5 7.5M13 2v3h-3" stroke={color} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  ),
  Mail: ({ size = 14, color = 'currentColor' }) => (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none">
      <rect x="2" y="3.5" width="12" height="9" rx="2" stroke={color} strokeWidth="1.3"/>
      <path d="M3.5 5l4.5 3.5L12.5 5" stroke={color} strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  ),
  Trash: ({ size = 14, color = 'currentColor' }) => (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none">
      <path d="M3.5 4.5h9M6 2.8h4M5 4.5v7.2M8 4.5v7.2M11 4.5v7.2M4.2 4.5l.4 8a1 1 0 001 .95h4.8a1 1 0 001-.95l.4-8" stroke={color} strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  ),
  Clock: ({ size = 14, color = 'currentColor' }) => (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none">
      <circle cx="8" cy="8" r="5.5" stroke={color} strokeWidth="1.3"/>
      <path d="M8 5v3.2l2 1.3" stroke={color} strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  ),
  Train: ({ size = 12, color = 'currentColor' }) => (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none">
      <rect x="3" y="2" width="10" height="10" rx="2" stroke={color} strokeWidth="1.3"/>
      <path d="M3 9h10M6 14l-1 1M10 14l1 1" stroke={color} strokeWidth="1.3" strokeLinecap="round"/>
      <circle cx="6" cy="11" r="0.8" fill={color}/>
      <circle cx="10" cy="11" r="0.8" fill={color}/>
    </svg>
  ),
};

Object.assign(window, {
  REGIONS,
  Icon,
  apiFetch,
  subscribeApiFetch,
  parseRentRange,
  manYen,
  resolveImg,
  API_BASE,
  SUBSCRIBE_API_BASE,
  getWatchSession,
  setWatchSession,
  clearWatchSession,
  formatDateTimeZh,
  normalizeDistrictName,
  buildDistrictOptions,
});
