import { logError, logInfo } from '../../utils';
import { NAVER_INDUSTRY_NAMES } from './stockSectors';

/**
 * Naver Finance 비공식 JSON API 로 개별 종목 펀더멘털 fetch.
 *
 * 두 endpoint 합성:
 *   - `/api/stock/<code>/integration` — 시총 텍스트 / PER / PBR / EPS / 현재가
 *   - `/api/stock/<code>/finance/annual` — ROE / 영업이익률 / 유보율 / 부채비율
 *     (rowList 안의 row.title 매칭, 최근 연도 컬럼 값 사용)
 *
 * JSON 응답이라 selector 깨질 일이 없고, label 매칭도 정확 (rowList[i].title === 'ROE').
 * 사용자가 별도 인증 / API 키 필요 없음 — Naver Finance 모바일 페이지가 쓰는 그대로.
 */

const USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
const INTEGRATION_URL = 'https://m.stock.naver.com/api/stock';

export interface Fundamentals {
    symbol: string;
    /** 연간 재무제표 (최근 *확정* 연도). */
    roe?: number;              // %
    operatingMargin?: number;  // % (영업이익률)
    retentionRatio?: number;   // % (유보율)
    debtRatio?: number;        // % (부채비율)
    /** 최근 확정 2개 연도 기준 YoY 성장률 (%). '성장성' 기준의 실측치 — 마진 수준이 아닌 진짜 성장. */
    revenueGrowthYoY?: number;   // 매출액 YoY %
    opProfitGrowthYoY?: number;  // 영업이익 YoY %
    /** integration API 의 현재가 + 평가지표. */
    per?: number;
    pbr?: number;
    eps?: number;
    marketCapEok?: number;     // 억 단위 (한국 경로 전용 — 미국은 marketCapNative 사용)
    currentPrice?: number;
    /** 업종 hint — 사용 가능하면 채움 ("기술력" 키워드 매칭 용). */
    sectorHint?: string;
    /** 시장 — 'KR'(Naver) | 'US'(Yahoo). 미지정 시 호출자가 심볼로 판별. */
    market?: 'KR' | 'US';
    /** 시가총액 native 단위 (US=USD). KR 은 marketCapEok 사용. */
    marketCapNative?: number;
    /** 통화 — currentPrice/marketCapNative 의 단위. */
    currency?: 'KRW' | 'USD';
    /** 데이터 출처 라벨 — 'Naver' | 'Yahoo quoteSummary'. 정확도/투명성 표기용. */
    source?: string;
}

interface NaverIntegrationResponse {
    stockName?: string;
    totalInfos?: Array<{ code: string; key: string; value: string }>;
    /** 네이버 업종 코드 (숫자). 통합 응답의 실제 필드 — industryInfo 는 존재하지 않음. */
    industryCode?: number | string;
}

interface NaverFinanceAnnualResponse {
    financeInfo?: {
        trTitleList?: Array<{ isConsensus: 'Y' | 'N'; title: string; key: string }>;
        rowList?: Array<{ title: string; columns: Record<string, { value: string }> }>;
    };
}

/** "12,090" / "23.64배" / "5,800%" / "1,710조 365억" / "-" 텍스트에서 숫자 추출. */
function parseNumber(raw: string | undefined): number | undefined {
    if (!raw) return undefined;
    const cleaned = raw.replace(/,/g, '').replace(/배|%|원|억|조/g, '').trim();
    if (!cleaned || cleaned === '-' || cleaned === 'N/A') return undefined;
    const n = parseFloat(cleaned);
    return Number.isFinite(n) ? n : undefined;
}

/** "1,710조 365억" / "2,787억" / "5조" → 억 단위 정수. */
function parseMarketCapText(text: string | undefined): number | undefined {
    if (!text) return undefined;
    const cleaned = text.replace(/원|\s/g, '');
    const joMatch = cleaned.match(/([\d,]+)조/);
    const eokMatch = cleaned.match(/(?:조)?([\d,]+)억/) || cleaned.match(/([\d,]+)$/);
    const jo = joMatch ? parseInt(joMatch[1].replace(/,/g, ''), 10) : 0;
    const eok = eokMatch ? parseInt(eokMatch[1].replace(/,/g, ''), 10) : 0;
    const total = jo * 10000 + eok;
    return total > 0 ? total : undefined;
}

/** trTitleList 에서 *최근 확정* (isConsensus = 'N') 컬럼 키 선택. */
function pickLatestConfirmedKey(titles?: Array<{ isConsensus: 'Y' | 'N'; key: string }>): string | null {
    if (!titles || titles.length === 0) return null;
    // 'N' 만 필터 → key 내림차순 → 첫 번째.
    const confirmed = titles.filter(t => t.isConsensus === 'N').map(t => t.key).sort().reverse();
    return confirmed[0] ?? null;
}

async function fetchIntegration(symbol: string, timeoutMs: number): Promise<NaverIntegrationResponse | null> {
    try {
        const res = await fetch(`${INTEGRATION_URL}/${symbol}/integration`, {
            headers: { 'User-Agent': USER_AGENT, 'Accept': 'application/json' },
            signal: AbortSignal.timeout(timeoutMs),
        });
        if (!res.ok) return null;
        return await res.json() as NaverIntegrationResponse;
    } catch (e: any) {
        logError('Naver integration fetch 실패.', { symbol, error: e?.message ?? String(e) });
        return null;
    }
}

async function fetchFinanceAnnual(symbol: string, timeoutMs: number): Promise<NaverFinanceAnnualResponse | null> {
    try {
        const res = await fetch(`${INTEGRATION_URL}/${symbol}/finance/annual`, {
            headers: { 'User-Agent': USER_AGENT, 'Accept': 'application/json' },
            signal: AbortSignal.timeout(timeoutMs),
        });
        if (!res.ok) return null;
        return await res.json() as NaverFinanceAnnualResponse;
    } catch (e: any) {
        logError('Naver finance annual fetch 실패.', { symbol, error: e?.message ?? String(e) });
        return null;
    }
}

export async function fetchFundamentals(symbol: string, timeoutMs = 10000): Promise<Fundamentals | null> {
    const [integ, fin] = await Promise.all([
        fetchIntegration(symbol, timeoutMs),
        fetchFinanceAnnual(symbol, timeoutMs),
    ]);
    if (!integ && !fin) return null;

    const out: Fundamentals = { symbol, market: 'KR', currency: 'KRW', source: 'Naver' };

    // integration — totalInfos 의 code 로 추출 (key 한글 텍스트보다 안정적).
    if (integ?.totalInfos) {
        const map = new Map(integ.totalInfos.map(i => [i.code, i.value]));
        out.per = parseNumber(map.get('per'));
        out.pbr = parseNumber(map.get('pbr'));
        out.eps = parseNumber(map.get('eps'));
        out.currentPrice = parseNumber(map.get('closePrice') || map.get('lastClosePrice'));
        out.marketCapEok = parseMarketCapText(map.get('marketValue'));
    }
    // 업종 — 통합 응답의 industryCode(숫자) → 업종명 매핑. (구버전은 없는 industryInfo.name
    // 을 읽어 항상 빈 값이었음 → '기술력' 키워드·섹터 표시가 동작 안 했던 버그 수정.)
    if (integ?.industryCode !== undefined) {
        const code = typeof integ.industryCode === 'string' ? parseInt(integ.industryCode, 10) : integ.industryCode;
        if (Number.isFinite(code) && NAVER_INDUSTRY_NAMES[code]) out.sectorHint = NAVER_INDUSTRY_NAMES[code];
    }

    // finance/annual — rowList 에서 최근 확정 연도 컬럼 값.
    if (fin?.financeInfo?.rowList && fin.financeInfo.rowList.length > 0) {
        const confirmedKeys = (fin.financeInfo.trTitleList || [])
            .filter(t => t.isConsensus === 'N').map(t => t.key).sort().reverse();
        const latestKey = confirmedKeys[0] ?? null;
        const prevKey = confirmedKeys[1] ?? null;
        if (latestKey) {
            const rowByTitle = new Map(fin.financeInfo.rowList.map(r => [r.title, r]));
            const valueOf = (title: string, key: string = latestKey): number | undefined => {
                const row = rowByTitle.get(title);
                if (!row) return undefined;
                return parseNumber(row.columns[key]?.value);
            };
            out.roe = valueOf('ROE');
            out.operatingMargin = valueOf('영업이익률');
            out.retentionRatio = valueOf('유보율');
            out.debtRatio = valueOf('부채비율');
            // YoY 성장률 — 최근 확정 2개 연도. '성장성'을 마진 수준이 아닌 실측 성장으로 판정.
            if (prevKey) {
                const yoy = (title: string): number | undefined => {
                    const a = valueOf(title, latestKey);
                    const b = valueOf(title, prevKey);
                    if (a === undefined || b === undefined || b === 0) return undefined;
                    return ((a - b) / Math.abs(b)) * 100;
                };
                out.revenueGrowthYoY = yoy('매출액');
                out.opProfitGrowthYoY = yoy('영업이익');
            }
        }
    }
    return out;
}

/** 일괄 fetch — throttle 300ms. JSON API 가 가벼우니 HTML 크롤 500ms 보다 빠르게. */
export async function fetchAllFundamentals(
    symbols: string[],
    onProgress?: (symbol: string, fund: Fundamentals | null, i: number, total: number) => void,
): Promise<Map<string, Fundamentals>> {
    const out = new Map<string, Fundamentals>();
    let i = 0;
    for (const symbol of symbols) {
        i++;
        const fund = await fetchFundamentals(symbol);
        if (fund) out.set(symbol, fund);
        onProgress?.(symbol, fund, i, symbols.length);
        await new Promise(r => setTimeout(r, 300));
    }
    logInfo(`Naver fundamentals 일괄 fetch: ${out.size}/${symbols.length} 성공.`);
    return out;
}
