import { randomUUID } from 'node:crypto';
import { config } from '../config/index.js';
import logger from '../utils/logger.js';
import {
    MANUAL_ENTRY_CONTAINER,
    buildBaseDocument,
    buildDocId,
    clampNumber,
    queryDocuments,
    toOptionalString,
    upsertDocument
} from './tradingRecordStore.js';
import { logTransaction } from './runtimeOrderRepository.js';

export interface ManualEntryRecord {
    stock_instance_id: string;
    symbol: string;
    active: boolean;
    user_id: string;
    profile_id?: string | null;
    buy_price?: number | null;
    sell_price?: number | null;
    buy_time?: string | null;
    sell_time?: string | null;
    quantity?: number | null;
    amount_usd?: number | null;
    sizing_mode?: string | null;
    filled_quantity?: number | null;
    notes?: string | null;
    status: string;
    is_crypto: boolean;
    is_real_trade: boolean;
    label?: string | null;
    entry_price?: number | null;
    reference_price?: number | null;
    gain_threshold_for_sell?: number | null;
    drop_threshold_for_buy?: number | null;
    workflow_type?: string | null;
    simple_side?: string | null;
    drop_trigger_mode?: string | null;
    profit_target_mode?: string | null;
    linked_trade_id?: string | null;
    holding_mode?: string | null;
    automation_state?: string | null;
}

type ManualEntryDocument = ManualEntryRecord & {
    id: string;
    productId: string;
    type: 'manual_entry';
    created_at: string;
    updated_at: string;
};

function normalizeNullableNumber(value: unknown): number | null | undefined {
    if (value === undefined) return undefined;
    if (value === null || value === '') return null;
    const num = Number(value);
    return Number.isFinite(num) ? num : null;
}

function normalizeNullableString(value: unknown): string | null | undefined {
    if (value === undefined) return undefined;
    if (value === null) return null;
    const text = String(value).trim();
    return text ? text : null;
}

function deriveSimpleAutomationState(status: string, holdingMode: string | null | undefined): string | null {
    const normalizedStatus = String(status || '').trim().toLowerCase();
    const normalizedMode = String(holdingMode || '').trim().toLowerCase();
    if (normalizedMode === 'long_term') {
        return normalizedStatus === 'sellcompleted' ? 'closed' : 'paused_long_term';
    }
    switch (normalizedStatus) {
        case 'simple_armed_buy':
        case 'simple_armed_sell':
            return 'armed';
        case 'simple_entry_submitted':
            return 'entry_submitted';
        case 'simple_bought':
            return 'holding_managed';
        case 'simple_exit_submitted':
            return 'exit_submitted';
        case 'sellcompleted':
            return 'closed';
        default:
            return null;
    }
}

function normalizeEntry(userId: string, input: Partial<ManualEntryRecord>, existing?: ManualEntryRecord | null): ManualEntryRecord {
    const workflowType = normalizeNullableString(input.workflow_type ?? existing?.workflow_type);
    const holdingMode = normalizeNullableString(
        input.holding_mode
        ?? existing?.holding_mode
        ?? (String(workflowType || '').trim().toLowerCase() === 'simple' ? 'short_term' : null)
    );
    const status = String(input.status || existing?.status || 'active');
    const automationState = normalizeNullableString(
        input.automation_state
        ?? existing?.automation_state
        ?? deriveSimpleAutomationState(status, holdingMode)
    );
    return {
        stock_instance_id: String(input.stock_instance_id || existing?.stock_instance_id || randomUUID()),
        symbol: String(input.symbol || existing?.symbol || '').trim(),
        active: Boolean(input.active ?? existing?.active ?? true),
        user_id: userId,
        profile_id: normalizeNullableString(input.profile_id ?? existing?.profile_id),
        buy_price: normalizeNullableNumber(input.buy_price ?? existing?.buy_price),
        sell_price: normalizeNullableNumber(input.sell_price ?? existing?.sell_price),
        buy_time: normalizeNullableString(input.buy_time ?? existing?.buy_time),
        sell_time: normalizeNullableString(input.sell_time ?? existing?.sell_time),
        quantity: normalizeNullableNumber(input.quantity ?? existing?.quantity),
        amount_usd: normalizeNullableNumber(input.amount_usd ?? existing?.amount_usd),
        sizing_mode: normalizeNullableString(input.sizing_mode ?? existing?.sizing_mode),
        filled_quantity: normalizeNullableNumber(input.filled_quantity ?? existing?.filled_quantity),
        notes: normalizeNullableString(input.notes ?? existing?.notes),
        status,
        is_crypto: Boolean(input.is_crypto ?? existing?.is_crypto ?? false),
        is_real_trade: Boolean(input.is_real_trade ?? existing?.is_real_trade ?? false),
        label: normalizeNullableString(input.label ?? existing?.label),
        entry_price: normalizeNullableNumber(input.entry_price ?? existing?.entry_price),
        reference_price: normalizeNullableNumber(input.reference_price ?? existing?.reference_price),
        gain_threshold_for_sell: normalizeNullableNumber(input.gain_threshold_for_sell ?? existing?.gain_threshold_for_sell),
        drop_threshold_for_buy: normalizeNullableNumber(input.drop_threshold_for_buy ?? existing?.drop_threshold_for_buy),
        workflow_type: workflowType,
        simple_side: normalizeNullableString(input.simple_side ?? existing?.simple_side),
        drop_trigger_mode: normalizeNullableString(input.drop_trigger_mode ?? existing?.drop_trigger_mode),
        profit_target_mode: normalizeNullableString(input.profit_target_mode ?? existing?.profit_target_mode),
        linked_trade_id: normalizeNullableString(input.linked_trade_id ?? existing?.linked_trade_id),
        holding_mode: holdingMode,
        automation_state: automationState,
    };
}

async function listManualEntryDocuments(userId: string): Promise<ManualEntryDocument[]> {
    const query = 'SELECT * FROM c WHERE c.productId = @productId AND c.type = @type AND c.user_id = @userId ORDER BY c.created_at DESC';
    return await queryDocuments<ManualEntryDocument>(MANUAL_ENTRY_CONTAINER, query, [
        { name: '@productId', value: config.PRODUCT_ID },
        { name: '@type', value: 'manual_entry' },
        { name: '@userId', value: userId },
    ]);
}

async function listAllManualEntryDocuments(): Promise<ManualEntryDocument[]> {
    const query = 'SELECT * FROM c WHERE c.productId = @productId AND c.type = @type ORDER BY c.created_at DESC';
    return await queryDocuments<ManualEntryDocument>(MANUAL_ENTRY_CONTAINER, query, [
        { name: '@productId', value: config.PRODUCT_ID },
        { name: '@type', value: 'manual_entry' },
    ]);
}

async function findManualEntryDocument(userId: string, entryId: string): Promise<ManualEntryDocument | null> {
    const rows = await queryDocuments<ManualEntryDocument>(MANUAL_ENTRY_CONTAINER, 'SELECT TOP 1 * FROM c WHERE c.productId = @productId AND c.type = @type AND c.user_id = @userId AND c.stock_instance_id = @entryId', [
        { name: '@productId', value: config.PRODUCT_ID },
        { name: '@type', value: 'manual_entry' },
        { name: '@userId', value: userId },
        { name: '@entryId', value: entryId },
    ]);
    return rows[0] || null;
}

async function insertHistoryRecord(userId: string, entry: ManualEntryRecord, reason: 'Manual Log' | 'Manual Close'): Promise<void> {
    const entryPrice = clampNumber(entry.buy_price);
    const exitPrice = clampNumber(entry.sell_price);
    const size = clampNumber(entry.quantity);
    if (!(entryPrice > 0) || !(exitPrice > 0) || !(size > 0)) {
        return;
    }

    const pnl = (exitPrice - entryPrice) * size;
    const pnlPercent = entryPrice > 0 ? ((exitPrice - entryPrice) / entryPrice) * 100 : 0;
    await logTransaction({
        user_id: userId,
        symbol: entry.symbol,
        side: 'BUY',
        entry_price: entryPrice,
        exit_price: exitPrice,
        size,
        pnl,
        pnl_percent: pnlPercent,
        reason,
        timestamp: Date.now(),
        source: 'MANUAL'
    });
}

export async function listManualEntriesForUser(userId: string): Promise<ManualEntryRecord[]> {
    const rows = await listManualEntryDocuments(userId);
    return rows as ManualEntryRecord[];
}

export async function listManualEntries(options?: { userId?: string }): Promise<ManualEntryRecord[]> {
    const rows = options?.userId
        ? await listManualEntryDocuments(options.userId)
        : await listAllManualEntryDocuments();
    return rows as ManualEntryRecord[];
}

export async function saveManualEntryForUser(userId: string, input: Partial<ManualEntryRecord>): Promise<ManualEntryRecord> {
    const entryId = String(input.stock_instance_id || '').trim();
    const existing = entryId ? await findManualEntryDocument(userId, entryId) : null;
    const normalized = normalizeEntry(userId, input, existing);
    if (!normalized.symbol) {
        throw new Error('Symbol is required');
    }

    const payload = buildBaseDocument('manual_entry', {
        ...normalized,
        stock_instance_id: normalized.stock_instance_id,
    }, existing?.id || buildDocId('manual_entry', userId, normalized.stock_instance_id));

    await upsertDocument<ManualEntryDocument>(MANUAL_ENTRY_CONTAINER, payload as ManualEntryDocument);

    if (existing) {
        if (normalized.sell_price && !existing.sell_price && normalized.buy_price) {
            await insertHistoryRecord(userId, normalized, 'Manual Close');
        }
    } else if (normalized.sell_price && normalized.buy_price) {
        await insertHistoryRecord(userId, normalized, 'Manual Log');
    }

    return normalized;
}

export async function deleteManualEntryForUser(userId: string, entryId: string): Promise<void> {
    const existing = await findManualEntryDocument(userId, entryId);
    if (!existing) {
        return;
    }
    const tombstone = {
        ...existing,
        active: false,
        status: 'deleted',
        updated_at: new Date().toISOString(),
        deleted_at: new Date().toISOString(),
    };
    await upsertDocument<ManualEntryDocument>(MANUAL_ENTRY_CONTAINER, tombstone);
    logger.info(`[ManualEntries] Marked ${toOptionalString(entryId) || 'unknown'} deleted in Cosmos`);
}
