import { getContainer } from '@bytelyst/cosmos';
import { randomUUID } from 'node:crypto';
import { config } from '../config/index.js';
import logger from '../utils/logger.js';
import type { supabaseService } from './SupabaseService.js';

type LegacySupabaseService = typeof supabaseService;

export interface TradingUserProfile {
    user_id: string;
    first_name: string;
    last_name: string;
    email: string;
    role: string;
    trade_enable: boolean;
    ALPACA_API_KEY?: string;
    ALPACA_SECRET_KEY?: string;
    REAL_ALPACA_API_KEY?: string;
    REAL_ALPACA_SECRET_KEY?: string;
    drop_threshold_for_buy?: number;
    gain_threshold_for_sell?: number;
    market_poll_interval_in_seconds?: number;
}

export interface TradeProfileRecord {
    id: string;
    user_id: string;
    name: string;
    allocated_capital: number;
    risk_per_trade_percent: number;
    symbols: string;
    is_active: boolean;
    strategy_config: Record<string, unknown>;
    created_at?: string;
    updated_at?: string;
}

interface TradeProfileDocument extends TradeProfileRecord {
    productId: string;
    type: 'trade_profile';
    createdAt: string;
    updatedAt: string;
}

const PROFILE_CONTAINER = 'trade_profiles';

function isCosmosConfigured(): boolean {
    return Boolean(config.COSMOS_ENDPOINT && config.COSMOS_KEY);
}

function normalizeProfile(row: Partial<TradeProfileRecord> | null | undefined): TradeProfileRecord | null {
    const id = String(row?.id || '').trim();
    const userId = String(row?.user_id || '').trim();
    if (!id || !userId) {
        return null;
    }

    return {
        id,
        user_id: userId,
        name: String(row?.name || 'Untitled Strategy').trim() || 'Untitled Strategy',
        allocated_capital: Number(row?.allocated_capital || 0),
        risk_per_trade_percent: Number(row?.risk_per_trade_percent || 0),
        symbols: String(row?.symbols || 'BTC/USDT'),
        is_active: Boolean(row?.is_active),
        strategy_config: (row?.strategy_config && typeof row.strategy_config === 'object')
            ? row.strategy_config as Record<string, unknown>
            : {},
        created_at: row?.created_at ? String(row.created_at) : undefined,
        updated_at: row?.updated_at ? String(row.updated_at) : undefined,
    };
}

function buildDefaultTradeProfile(userId: string): TradeProfileRecord {
    const timestamp = new Date().toISOString();
    return {
        id: randomUUID(),
        user_id: userId,
        name: 'My First Strategy',
        allocated_capital: 1000,
        risk_per_trade_percent: 1,
        symbols: 'BTC/USDT, ETH/USDT',
        is_active: false,
        strategy_config: {
            rules: [
                { ruleId: 'TrendBiasRule', enabled: true, params: { fastPeriod: 50, slowPeriod: 200 } },
                { ruleId: 'MomentumRule', enabled: true, params: { rsiPeriod: 14, overbought: 70, oversold: 30 } },
                { ruleId: 'ZoneRule', enabled: true, params: { zonePercent: 1.5 } },
                { ruleId: 'SessionRule', enabled: true, params: { sessions: 'London,NY' } },
                { ruleId: 'EntryTriggerRule', enabled: true, params: { showPatterns: true } },
                { ruleId: 'RiskManagementRule', enabled: true, params: { maxRisk: 2.0 } },
                { ruleId: 'AIAnalysisRule', enabled: false, params: { minConfidence: 0.7 } },
            ],
            riskLimits: { maxDailyLossUsd: 50, maxOpenTrades: 3, maxConsecutiveLosses: 2 },
            execution: { orderType: 'market', cooldownMinutes: 30, entryMode: 'both' },
        },
        created_at: timestamp,
        updated_at: timestamp,
    };
}

async function listProfilesFromCosmos(userId: string): Promise<TradeProfileRecord[]> {
    if (!isCosmosConfigured()) {
        return [];
    }

    const container = getContainer(PROFILE_CONTAINER);
    const { resources } = await container.items.query<TradeProfileDocument>({
        query: 'SELECT * FROM c WHERE c.productId = @productId AND c.user_id = @userId AND c.type = @type ORDER BY c.createdAt DESC',
        parameters: [
            { name: '@productId', value: config.PRODUCT_ID },
            { name: '@userId', value: userId },
            { name: '@type', value: 'trade_profile' },
        ],
    }).fetchAll();

    return resources
        .map((resource) => normalizeProfile({
            ...resource,
            created_at: resource.createdAt,
            updated_at: resource.updatedAt,
        }))
        .filter((profile): profile is TradeProfileRecord => Boolean(profile));
}

async function listAllProfilesFromCosmos(): Promise<TradeProfileRecord[]> {
    if (!isCosmosConfigured()) {
        return [];
    }

    const container = getContainer(PROFILE_CONTAINER);
    const { resources } = await container.items.query<TradeProfileDocument>({
        query: 'SELECT * FROM c WHERE c.productId = @productId AND c.type = @type ORDER BY c.createdAt DESC',
        parameters: [
            { name: '@productId', value: config.PRODUCT_ID },
            { name: '@type', value: 'trade_profile' },
        ],
    }).fetchAll();

    return resources
        .map((resource) => normalizeProfile({
            ...resource,
            created_at: resource.createdAt,
            updated_at: resource.updatedAt,
        }))
        .filter((profile): profile is TradeProfileRecord => Boolean(profile));
}

async function listProfilesFromSupabase(userId: string, legacyService?: LegacySupabaseService): Promise<TradeProfileRecord[]> {
    const client = legacyService?.getClient?.();
    if (!client) {
        return [];
    }

    try {
        const { data, error } = await client
            .from('trade_profiles')
            .select('id,user_id,name,allocated_capital,risk_per_trade_percent,symbols,is_active,strategy_config,created_at,updated_at')
            .eq('user_id', userId)
            .order('created_at', { ascending: false });

        if (error || !Array.isArray(data)) {
            return [];
        }

        return data
            .map((row) => normalizeProfile(row as TradeProfileRecord))
            .filter((profile): profile is TradeProfileRecord => Boolean(profile));
    } catch (error) {
        logger.warn(`[Profiles] Legacy profile read failed: ${error instanceof Error ? error.message : 'unknown error'}`);
        return [];
    }
}

async function listAllProfilesFromSupabase(legacyService?: LegacySupabaseService): Promise<TradeProfileRecord[]> {
    const client = legacyService?.getClient?.();
    if (!client) {
        return [];
    }

    try {
        const { data, error } = await client
            .from('trade_profiles')
            .select('id,user_id,name,allocated_capital,risk_per_trade_percent,symbols,is_active,strategy_config,created_at,updated_at')
            .order('created_at', { ascending: false });

        if (error || !Array.isArray(data)) {
            return [];
        }

        return data
            .map((row) => normalizeProfile(row as TradeProfileRecord))
            .filter((profile): profile is TradeProfileRecord => Boolean(profile));
    } catch (error) {
        logger.warn(`[Profiles] Legacy global profile read failed: ${error instanceof Error ? error.message : 'unknown error'}`);
        return [];
    }
}

async function mirrorProfileToSupabase(profile: TradeProfileRecord, legacyService?: LegacySupabaseService): Promise<void> {
    const client = legacyService?.getClient?.();
    if (!client) return;

    try {
        const { error } = await client
            .from('trade_profiles')
            .upsert({
                ...profile,
                created_at: profile.created_at || new Date().toISOString(),
                updated_at: profile.updated_at || new Date().toISOString(),
            }, { onConflict: 'id' });

        if (error) {
            logger.warn(`[Profiles] Legacy profile mirror failed: ${error.message}`);
        }
    } catch (error) {
        logger.warn(`[Profiles] Legacy profile mirror failed: ${error instanceof Error ? error.message : 'unknown error'}`);
    }
}

async function deleteProfileFromSupabase(profileId: string, userId: string, legacyService?: LegacySupabaseService): Promise<void> {
    const client = legacyService?.getClient?.();
    if (!client) return;

    try {
        const { error } = await client
            .from('trade_profiles')
            .delete()
            .eq('id', profileId)
            .eq('user_id', userId);

        if (error) {
            logger.warn(`[Profiles] Legacy profile delete failed: ${error.message}`);
        }
    } catch (error) {
        logger.warn(`[Profiles] Legacy profile delete failed: ${error instanceof Error ? error.message : 'unknown error'}`);
    }
}

export async function listTradeProfilesForUser(userId: string, legacyService?: LegacySupabaseService): Promise<TradeProfileRecord[]> {
    try {
        const cosmosProfiles = await listProfilesFromCosmos(userId);
        if (cosmosProfiles.length > 0) {
            return cosmosProfiles;
        }
    } catch (error) {
        logger.warn(`[Profiles] Cosmos profile read failed, falling back to legacy store: ${error instanceof Error ? error.message : 'unknown error'}`);
    }

    return listProfilesFromSupabase(userId, legacyService);
}

export async function listAllTradeProfiles(legacyService?: LegacySupabaseService): Promise<TradeProfileRecord[]> {
    try {
        const cosmosProfiles = await listAllProfilesFromCosmos();
        if (cosmosProfiles.length > 0) {
            return cosmosProfiles;
        }
    } catch (error) {
        logger.warn(`[Profiles] Cosmos global profile read failed, falling back to legacy store: ${error instanceof Error ? error.message : 'unknown error'}`);
    }

    return listAllProfilesFromSupabase(legacyService);
}

export async function ensureDefaultTradeProfileForUser(userId: string, legacyService?: LegacySupabaseService): Promise<TradeProfileRecord[]> {
    const profiles = await listTradeProfilesForUser(userId, legacyService);
    if (profiles.length > 0) {
        return profiles;
    }

    const created = await saveTradeProfileForUser(buildDefaultTradeProfile(userId), userId, legacyService);
    return [created];
}

export async function saveTradeProfileForUser(
    input: Partial<TradeProfileRecord>,
    userId: string,
    legacyService?: LegacySupabaseService
): Promise<TradeProfileRecord> {
    const now = new Date().toISOString();
    const normalized = normalizeProfile({
        ...input,
        id: String(input.id || randomUUID()),
        user_id: userId,
        created_at: input.created_at || now,
        updated_at: now,
    });

    if (!normalized) {
        throw new Error('Invalid trade profile payload');
    }

    if (isCosmosConfigured()) {
        try {
            const container = getContainer(PROFILE_CONTAINER);
            await container.items.upsert<TradeProfileDocument>({
                ...normalized,
                productId: config.PRODUCT_ID,
                type: 'trade_profile',
                createdAt: normalized.created_at || now,
                updatedAt: normalized.updated_at || now,
            });
        } catch (error) {
            logger.warn(`[Profiles] Cosmos profile upsert failed: ${error instanceof Error ? error.message : 'unknown error'}`);
        }
    }

    await mirrorProfileToSupabase(normalized, legacyService);
    return normalized;
}

export async function deleteTradeProfileForUser(
    profileId: string,
    userId: string,
    legacyService?: LegacySupabaseService
): Promise<void> {
    if (!profileId || !userId) {
        return;
    }

    if (isCosmosConfigured()) {
        try {
            const container = getContainer(PROFILE_CONTAINER);
            await container.item(profileId, userId).delete();
        } catch (error) {
            logger.warn(`[Profiles] Cosmos profile delete failed: ${error instanceof Error ? error.message : 'unknown error'}`);
        }
    }

    await deleteProfileFromSupabase(profileId, userId, legacyService);
}

export async function getCurrentUserProfile(
    userId: string,
    fallback: Partial<TradingUserProfile> = {},
    legacyService?: LegacySupabaseService
): Promise<TradingUserProfile> {
    const client = legacyService?.getClient?.();
    if (client) {
        try {
            const { data, error } = await client
                .from('users')
                .select('user_id,first_name,last_name,email,role,trade_enable,ALPACA_API_KEY,ALPACA_SECRET_KEY,REAL_ALPACA_API_KEY,REAL_ALPACA_SECRET_KEY,drop_threshold_for_buy,gain_threshold_for_sell,market_poll_interval_in_seconds')
                .eq('user_id', userId)
                .maybeSingle();

            if (!error && data) {
                return {
                    user_id: String((data as any).user_id || userId),
                    first_name: String((data as any).first_name || fallback.first_name || ''),
                    last_name: String((data as any).last_name || fallback.last_name || ''),
                    email: String((data as any).email || fallback.email || ''),
                    role: String((data as any).role || fallback.role || 'member'),
                    trade_enable: Boolean((data as any).trade_enable ?? fallback.trade_enable ?? true),
                    ALPACA_API_KEY: (data as any).ALPACA_API_KEY || fallback.ALPACA_API_KEY,
                    ALPACA_SECRET_KEY: (data as any).ALPACA_SECRET_KEY || fallback.ALPACA_SECRET_KEY,
                    REAL_ALPACA_API_KEY: (data as any).REAL_ALPACA_API_KEY || fallback.REAL_ALPACA_API_KEY,
                    REAL_ALPACA_SECRET_KEY: (data as any).REAL_ALPACA_SECRET_KEY || fallback.REAL_ALPACA_SECRET_KEY,
                    drop_threshold_for_buy: Number((data as any).drop_threshold_for_buy ?? fallback.drop_threshold_for_buy ?? 0),
                    gain_threshold_for_sell: Number((data as any).gain_threshold_for_sell ?? fallback.gain_threshold_for_sell ?? 0),
                    market_poll_interval_in_seconds: Number((data as any).market_poll_interval_in_seconds ?? fallback.market_poll_interval_in_seconds ?? 0),
                };
            }
        } catch (error) {
            logger.warn(`[Profiles] Legacy user profile read failed: ${error instanceof Error ? error.message : 'unknown error'}`);
        }
    }

    return {
        user_id: userId,
        first_name: String(fallback.first_name || ''),
        last_name: String(fallback.last_name || ''),
        email: String(fallback.email || ''),
        role: String(fallback.role || 'member'),
        trade_enable: Boolean(fallback.trade_enable ?? true),
        ALPACA_API_KEY: fallback.ALPACA_API_KEY,
        ALPACA_SECRET_KEY: fallback.ALPACA_SECRET_KEY,
        REAL_ALPACA_API_KEY: fallback.REAL_ALPACA_API_KEY,
        REAL_ALPACA_SECRET_KEY: fallback.REAL_ALPACA_SECRET_KEY,
        drop_threshold_for_buy: Number(fallback.drop_threshold_for_buy ?? 0),
        gain_threshold_for_sell: Number(fallback.gain_threshold_for_sell ?? 0),
        market_poll_interval_in_seconds: Number(fallback.market_poll_interval_in_seconds ?? 0),
    };
}

export async function saveCurrentUserProfile(
    userId: string,
    input: Partial<TradingUserProfile>,
    fallback: Partial<TradingUserProfile> = {},
    legacyService?: LegacySupabaseService
): Promise<TradingUserProfile> {
    const existing = await getCurrentUserProfile(userId, fallback, legacyService);
    const merged: TradingUserProfile = {
        ...existing,
        ...input,
        user_id: userId,
        email: String(input.email ?? existing.email ?? fallback.email ?? ''),
        role: String(input.role ?? existing.role ?? fallback.role ?? 'member'),
        first_name: String(input.first_name ?? existing.first_name ?? fallback.first_name ?? ''),
        last_name: String(input.last_name ?? existing.last_name ?? fallback.last_name ?? ''),
        trade_enable: Boolean(input.trade_enable ?? existing.trade_enable ?? fallback.trade_enable ?? true),
        drop_threshold_for_buy: Number(input.drop_threshold_for_buy ?? existing.drop_threshold_for_buy ?? fallback.drop_threshold_for_buy ?? 0),
        gain_threshold_for_sell: Number(input.gain_threshold_for_sell ?? existing.gain_threshold_for_sell ?? fallback.gain_threshold_for_sell ?? 0),
        market_poll_interval_in_seconds: Number(input.market_poll_interval_in_seconds ?? existing.market_poll_interval_in_seconds ?? fallback.market_poll_interval_in_seconds ?? 0),
    };

    const client = legacyService?.getClient?.();
    if (client) {
        try {
            const { error } = await client
                .from('users')
                .upsert({
                    user_id: userId,
                    first_name: merged.first_name,
                    last_name: merged.last_name,
                    email: merged.email,
                    role: merged.role,
                    trade_enable: merged.trade_enable,
                    ALPACA_API_KEY: merged.ALPACA_API_KEY ?? null,
                    ALPACA_SECRET_KEY: merged.ALPACA_SECRET_KEY ?? null,
                    REAL_ALPACA_API_KEY: merged.REAL_ALPACA_API_KEY ?? null,
                    REAL_ALPACA_SECRET_KEY: merged.REAL_ALPACA_SECRET_KEY ?? null,
                    drop_threshold_for_buy: merged.drop_threshold_for_buy,
                    gain_threshold_for_sell: merged.gain_threshold_for_sell,
                    market_poll_interval_in_seconds: merged.market_poll_interval_in_seconds,
                }, { onConflict: 'user_id' });

            if (error) {
                throw new Error(error.message);
            }
        } catch (error) {
            logger.warn(`[Profiles] Legacy user profile save failed: ${error instanceof Error ? error.message : 'unknown error'}`);
        }
    }

    return merged;
}
