import 'server-only';
import { FieldValue } from 'firebase-admin/firestore';
import { getFirebaseAdmin } from '@/lib/firebase-admin';

// ─────────────────────────────────────────────
// 타입 정의
// ─────────────────────────────────────────────

export interface ApiUsageDaily {
    date: string;                          // "YYYY-MM-DD"
    firestoreReads: number;
    firestoreWrites: number;
    geminiEmbeddingCalls: number;
    geminiGenerationCalls: number;
    queryCalls: number;
    cacheHits: number;
    cacheMisses: number;
    estimatedCostUsd: number;
    hourlyQueryCounts: Record<string, number>; // 키: "00"~"23"
    updatedAt?: FirebaseFirestore.Timestamp;
}

export type UsageType =
    | 'firestoreRead'
    | 'firestoreWrite'
    | 'geminiEmbedding'
    | 'geminiGeneration'
    | 'query'
    | 'cacheHit'
    | 'cacheMiss';

export interface DailyUsageBudget {
    totalQueries: number;
    estimatedCostUsd: number;
    isOverBudget: boolean;
}

// ─────────────────────────────────────────────
// 비용 상수
// ─────────────────────────────────────────────

const COST_PER_UNIT: Record<string, number> = {
    firestoreRead: 0.00000036,    // $0.036 per 100K reads
    firestoreWrite: 0.00000108,   // $0.108 per 100K writes
    geminiEmbedding: 0.000001,    // ~$0.001 per 1K tokens (text-embedding-004)
    geminiGeneration: 0.0000075,  // ~$0.0075 per 1K tokens (gemini-2.0-flash)
};

const COLLECTION = 'api_usage_daily';

// ─────────────────────────────────────────────
// 내부 헬퍼
// ─────────────────────────────────────────────

function getTodayDateString(): string {
    return new Date().toISOString().split('T')[0]; // "YYYY-MM-DD"
}

function getCurrentHourKey(): string {
    return new Date().getUTCHours().toString().padStart(2, '0');
}

/**
 * UsageType → Firestore 필드명 매핑
 */
function getFieldName(type: UsageType): string {
    const fieldMap: Record<UsageType, string> = {
        firestoreRead: 'firestoreReads',
        firestoreWrite: 'firestoreWrites',
        geminiEmbedding: 'geminiEmbeddingCalls',
        geminiGeneration: 'geminiGenerationCalls',
        query: 'queryCalls',
        cacheHit: 'cacheHits',
        cacheMiss: 'cacheMisses',
    };
    return fieldMap[type];
}

/**
 * 해당 타입에 대한 단위 비용 반환
 * query, cacheHit, cacheMiss 는 비용 계산에 직접 쓰이지 않으므로 0 반환
 */
function getCostPerUnit(type: UsageType): number {
    const costMap: Record<UsageType, number> = {
        firestoreRead: COST_PER_UNIT.firestoreRead,
        firestoreWrite: COST_PER_UNIT.firestoreWrite,
        geminiEmbedding: COST_PER_UNIT.geminiEmbedding,
        geminiGeneration: COST_PER_UNIT.geminiGeneration,
        query: 0,
        cacheHit: 0,
        cacheMiss: 0,
    };
    return costMap[type];
}

const MAX_DAILY_COST_USD = parseFloat(process.env.MAX_DAILY_COST_USD || '5');

// ─────────────────────────────────────────────
// Public API
// ─────────────────────────────────────────────

/**
 * 사용량 기록 — 각 API 호출 시 increment
 * FieldValue.increment()를 사용해 원자적으로 카운터를 증가시킵니다.
 */
export async function trackApiUsage(params: {
    type: UsageType;
    count?: number;
}): Promise<void> {
    const { type, count = 1 } = params;
    const date = getTodayDateString();
    const db = getFirebaseAdmin().firestore();
    const docRef = db.collection(COLLECTION).doc(date);

    const fieldName = getFieldName(type);
    const costDelta = getCostPerUnit(type) * count;

    const updatePayload: Record<string, FirebaseFirestore.FieldValue | string> = {
        date,
        [fieldName]: FieldValue.increment(count),
        estimatedCostUsd: FieldValue.increment(costDelta),
        updatedAt: FieldValue.serverTimestamp(),
    };

    // query 타입일 경우 시간대별 카운트도 함께 증가
    if (type === 'query') {
        const hourKey = getCurrentHourKey();
        updatePayload[`hourlyQueryCounts.${hourKey}`] = FieldValue.increment(count);
    }

    // merge: true → 문서가 없으면 생성, 있으면 해당 필드만 업데이트
    await docRef.set(updatePayload, { merge: true });
}

/**
 * 일일 사용량 조회
 * @param date "YYYY-MM-DD" 형식
 */
export async function getDailyUsage(date: string): Promise<ApiUsageDaily | null> {
    const db = getFirebaseAdmin().firestore();
    const snap = await db.collection(COLLECTION).doc(date).get();

    if (!snap.exists) {
        return null;
    }

    const data = snap.data()!;
    return {
        date: data.date ?? date,
        firestoreReads: data.firestoreReads ?? 0,
        firestoreWrites: data.firestoreWrites ?? 0,
        geminiEmbeddingCalls: data.geminiEmbeddingCalls ?? 0,
        geminiGenerationCalls: data.geminiGenerationCalls ?? 0,
        queryCalls: data.queryCalls ?? 0,
        cacheHits: data.cacheHits ?? 0,
        cacheMisses: data.cacheMisses ?? 0,
        estimatedCostUsd: data.estimatedCostUsd ?? 0,
        hourlyQueryCounts: data.hourlyQueryCounts ?? {},
        updatedAt: data.updatedAt,
    };
}

/**
 * 오늘의 사용량 + 예산 초과 여부 조회
 * route.ts에서 일일 하드 리밋 체크에 사용
 */
export async function getTodayUsage(): Promise<DailyUsageBudget> {
    const today = getTodayDateString();
    const usage = await getDailyUsage(today);

    if (!usage) {
        return { totalQueries: 0, estimatedCostUsd: 0, isOverBudget: false };
    }

    return {
        totalQueries: usage.queryCalls,
        estimatedCostUsd: usage.estimatedCostUsd,
        isOverBudget: usage.estimatedCostUsd >= MAX_DAILY_COST_USD,
    };
}

/**
 * 기간별 사용량 조회
 * @param period daily(1일) | weekly(7일) | monthly(30일)
 * @param date   기준 날짜 "YYYY-MM-DD" (default: 오늘)
 */
export async function getUsageSummary(params: {
    period: 'daily' | 'weekly' | 'monthly';
    date?: string;
}): Promise<{ data: ApiUsageDaily[]; totalCost: number; avgDailyCost: number }> {
    const { period, date } = params;
    const baseDate = date ? new Date(date) : new Date();

    // 기간에 따른 조회 일수 결정
    const dayCount = period === 'daily' ? 1 : period === 'weekly' ? 7 : 30;

    // 조회 대상 날짜 목록 생성 (baseDate 포함, 과거 방향)
    const dateStrings: string[] = [];
    for (let i = 0; i < dayCount; i++) {
        const d = new Date(baseDate);
        d.setUTCDate(d.getUTCDate() - i);
        dateStrings.push(d.toISOString().split('T')[0]);
    }

    const db = getFirebaseAdmin().firestore();
    const collection = db.collection(COLLECTION);

    // 병렬로 각 날짜 문서 조회
    const snapshots = await Promise.all(
        dateStrings.map((dateStr) => collection.doc(dateStr).get())
    );

    const data: ApiUsageDaily[] = snapshots
        .filter((snap) => snap.exists)
        .map((snap) => {
            const d = snap.data()!;
            return {
                date: d.date ?? snap.id,
                firestoreReads: d.firestoreReads ?? 0,
                firestoreWrites: d.firestoreWrites ?? 0,
                geminiEmbeddingCalls: d.geminiEmbeddingCalls ?? 0,
                geminiGenerationCalls: d.geminiGenerationCalls ?? 0,
                queryCalls: d.queryCalls ?? 0,
                cacheHits: d.cacheHits ?? 0,
                cacheMisses: d.cacheMisses ?? 0,
                estimatedCostUsd: d.estimatedCostUsd ?? 0,
                hourlyQueryCounts: d.hourlyQueryCounts ?? {},
                updatedAt: d.updatedAt,
            };
        });

    const totalCost = data.reduce((sum, row) => sum + row.estimatedCostUsd, 0);
    const avgDailyCost = data.length > 0 ? totalCost / data.length : 0;

    return { data, totalCost, avgDailyCost };
}

/**
 * 쿼리당 비용 추정
 * 임베딩비 + 검색 읽기비 + (캐시 미스 시 생성비)
 */
export async function estimateQueryCost(params: {
    embeddingCalls: number;
    firestoreReads: number;
    generationCalls: number;
    isCacheHit: boolean;
}): Promise<{ costUsd: number; breakdown: Record<string, number> }> {
    const { embeddingCalls, firestoreReads, generationCalls, isCacheHit } = params;

    const embeddingCost = embeddingCalls * COST_PER_UNIT.geminiEmbedding;
    const readCost = firestoreReads * COST_PER_UNIT.firestoreRead;
    // 캐시 히트 시 생성 비용 없음
    const generationCost = isCacheHit ? 0 : generationCalls * COST_PER_UNIT.geminiGeneration;

    const breakdown: Record<string, number> = {
        embeddingCost,
        firestoreReadCost: readCost,
        generationCost,
    };

    const costUsd = embeddingCost + readCost + generationCost;

    return { costUsd, breakdown };
}
