import { z } from 'zod';

const coerceAbv = z.preprocess((val) => {
    if (val === null || val === undefined || val === '') return null;
    const n = Number(val);
    if (isNaN(n)) return null;
    return n;
}, z.number().min(0).max(100).nullish());

const coerceAge = z.preprocess((val) => {
    if (val === null || val === undefined || val === '') return null;
    const n = Number(val);
    if (isNaN(n)) return null;
    // If it looks like a year (e.g. 19xx or 20xx), it's probably not the age
    if (n > 1900 && n < 2100) return null;
    return n;
}, z.number().min(0).max(200).nullish());

export const BottleMetadataSchema = z.object({
    name: z.string().trim().min(1).max(255).nullish(),
    distillery: z.string().trim().max(255).nullish(),
    bottler: z.string().trim().max(255).nullish(),
    series: z.string().trim().max(255).nullish(),
    category: z.string().trim().max(100).nullish(),
    abv: coerceAbv,
    age: coerceAge,
    vintage: z.string().trim().max(50).nullish(),
    bottleCode: z.string().trim().max(100).nullish(),
    whiskybaseId: z.string().trim().max(50).nullish(),
    distilled_at: z.string().trim().max(50).nullish(),
    bottled_at: z.string().trim().max(50).nullish(),
    batch_info: z.string().trim().max(255).nullish(),
    cask_type: z.string().trim().max(255).nullish(),
    is_whisky: z.boolean().default(true),
    confidence: z.number().min(0).max(100).default(100),
    confidence_scores: z.record(z.string(), z.number().min(0).max(100)).nullish(),
    purchase_price: z.number().min(0).nullish(),
    status: z.enum(['sealed', 'open', 'sampled', 'empty']).default('sealed').nullish(),
    suggested_tags: z.array(z.string().trim().max(100)).nullish(),
    suggested_custom_tags: z.array(z.string().trim().max(100)).nullish(),
});

export type BottleMetadata = z.infer<typeof BottleMetadataSchema>;

export const TastingNoteSchema = z.object({
    bottle_id: z.string().uuid(),
    session_id: z.string().uuid().optional(),
    rating: z.number().min(0).max(100),
    nose_notes: z.string().trim().max(2000).optional(),
    palate_notes: z.string().trim().max(2000).optional(),
    finish_notes: z.string().trim().max(2000).optional(),
    is_sample: z.boolean().optional().default(false),
    buddy_ids: z.array(z.string().uuid()).optional(),
    tag_ids: z.array(z.string().uuid()).optional(),
    tasted_at: z.string().datetime().optional(),
    blind_label: z.string().trim().max(100).nullish(),
    guess_abv: z.number().min(0).max(100).nullish(),
    guess_age: z.number().min(0).max(200).nullish(),
    guess_region: z.string().trim().max(100).nullish(),
    guess_points: z.number().min(0).nullish(),
    flavor_profile: z.object({
        smoky: z.number().min(0).max(100),
        fruity: z.number().min(0).max(100),
        spicy: z.number().min(0).max(100),
        sweet: z.number().min(0).max(100),
        floral: z.number().min(0).max(100),
    }).optional(),
});

export type TastingNoteData = z.infer<typeof TastingNoteSchema>;

export const UpdateBottleSchema = z.object({
    name: z.string().trim().min(1).max(255).nullish(),
    distillery: z.string().trim().max(255).nullish(),
    category: z.string().trim().max(100).nullish(),
    abv: coerceAbv,
    age: coerceAge,
    whiskybase_id: z.string().trim().max(50).nullish(),
    purchase_price: z.number().min(0).nullish(),
    distilled_at: z.string().trim().max(50).nullish(),
    bottled_at: z.string().trim().max(50).nullish(),
    batch_info: z.string().trim().max(255).nullish(),
    cask_type: z.string().trim().max(255).nullish(),
    status: z.enum(['sealed', 'open', 'sampled', 'empty']).nullish(),
});

export type UpdateBottleData = z.infer<typeof UpdateBottleSchema>;

export const TagSchema = z.object({
    name: z.string().trim().min(1).max(50),
    category: z.enum(['nose', 'taste', 'finish', 'texture']),
});

export type TagData = z.infer<typeof TagSchema>;

export const AdminCreditUpdateSchema = z.object({
    userId: z.string().uuid(),
    newBalance: z.number().min(0).max(1000000),
    reason: z.string().trim().min(1).max(255),
});

export type AdminCreditUpdateData = z.infer<typeof AdminCreditUpdateSchema>;

export const AdminSettingsSchema = z.object({
    userId: z.string().uuid(),
    dailyLimit: z.number().min(0).max(10000).nullable(),
    googleSearchCost: z.number().min(0).max(1000).optional(),
    geminiAiCost: z.number().min(0).max(1000).optional(),
});

export type AdminSettingsData = z.infer<typeof AdminSettingsSchema>;

export const DiscoveryDataSchema = z.object({
    name: z.string().trim().min(1).max(255),
    distillery: z.string().trim().max(255).nullish(),
    abv: coerceAbv,
    age: coerceAge,
    distilled_at: z.string().trim().max(50).nullish(),
    bottled_at: z.string().trim().max(50).nullish(),
    batch_info: z.string().trim().max(255).nullish(),
    cask_type: z.string().trim().max(255).nullish(),
});

export type DiscoveryData = z.infer<typeof DiscoveryDataSchema>;

export const BuddySchema = z.object({
    name: z.string().trim().min(1).max(100),
});

export type BuddyData = z.infer<typeof BuddySchema>;

export interface AnalysisResponse {
    success: boolean;
    data?: BottleMetadata;
    error?: string;
    isAiError?: boolean;
    imageHash?: string;
    perf?: {
        // Legacy fields (kept for backward compatibility)
        apiDuration?: number;
        parseDuration?: number;

        // Detailed metrics
        imagePrep?: number;
        cacheCheck?: number;
        encoding?: number;
        modelInit?: number;
        apiCall?: number;
        parsing?: number;
        validation?: number;
        dbOps?: number;
        uploadSize: number;
        total?: number;
        cacheHit?: boolean;
    };
    raw?: any;
}
