import { supabase, findOneGpi, queryGpi, insertGpi, updateGpi, deleteGpi } from '../config/supabase.js';

/**
 * Mongoose Compatibility Layer for Supabase (v2025)
 * Translates Mongoose-style calls to Supabase PostgREST queries.
 * Automatically handles camelCase (JS) to snake_case (DB) mapping for core fields.
 */
function createModel(tableName: string) {
    const mapToDb = (data: any) => {
        const mapped: any = { ...data };
        if (mapped.organizationId) { mapped.organization_id = mapped.organizationId; delete mapped.organizationId; }
        if (mapped.projectId) { mapped.project_id = mapped.projectId; delete mapped.projectId; }
        if (mapped.createdBy) { mapped.created_by = mapped.createdBy; delete mapped.createdBy; }
        if (mapped.createdAt) { mapped.created_at = mapped.createdAt; delete mapped.createdAt; }
        if (mapped.updatedAt) { mapped.updated_at = mapped.updatedAt; delete mapped.updatedAt; }
        return mapped;
    };

    const mapFromDb = (data: any) => {
        if (!data) return data;
        if (Array.isArray(data)) return data.map(mapFromDb);
        const mapped: any = { ...data, id: data.id || data._id };
        if (mapped.organization_id) mapped.organizationId = mapped.organization_id;
        if (mapped.project_id) mapped.projectId = mapped.project_id;
        if (mapped.created_by) mapped.createdBy = mapped.created_by;
        return mapped;
    };

    return {
        find: function(query: any = {}) {
            const dbQuery = mapToDb(query);
            const promise = (async () => {
                const { data, error } = await queryGpi(tableName, { filter: dbQuery });
                if (error) throw error;
                return mapFromDb(data || []);
            })();

            // Mock methods for chainability
            (promise as any).sort = () => promise;
            (promise as any).populate = () => promise;
            (promise as any).lean = () => promise;
            (promise as any).limit = () => promise;
            (promise as any).select = () => promise;
            
            return promise;
        },
        findOne: async (query: any) => {
            const data = await findOneGpi(tableName, mapToDb(query));
            return mapFromDb(data);
        },
        findById: async (id: string) => {
            const data = await findOneGpi(tableName, { id });
            return mapFromDb(data);
        },
        create: async (data: any) => {
            const dbData = mapToDb(data);
            const result = await insertGpi(tableName, dbData);
            return mapFromDb(result.data?.[0] || result.data);
        },
        insertMany: async (dataArray: any[]) => {
            const dbDataArray = dataArray.map(mapToDb);
            const { data, error } = await supabase.from(tableName).insert(dbDataArray).select();
            if (error) throw error;
            return mapFromDb(data);
        },
        deleteMany: async (query: any) => {
            const dbQuery = mapToDb(query);
            let q = supabase.from(tableName).delete();
            Object.keys(dbQuery).forEach(key => {
                q = q.eq(key, dbQuery[key]);
            });
            const { error } = await q;
            if (error) throw error;
            return { deletedCount: 0 }; // Supabase doesn't return count easily here
        },
        countDocuments: async (query: any = {}) => {
            const dbQuery = mapToDb(query);
            let q = supabase.from(tableName).select('*', { count: 'exact', head: true });
            Object.keys(dbQuery).forEach(key => {
                q = q.eq(key, dbQuery[key]);
            });
            const { count, error } = await q;
            if (error) throw error;
            return count || 0;
        },
        findOneAndUpdate: async (query: any, update: any) => {
            const existing = await findOneGpi(tableName, mapToDb(query));
            if (!existing) return null;
            const result = await updateGpi(tableName, existing.id, mapToDb(update));
            return mapFromDb(result.data?.[0]);
        },
        findByIdAndUpdate: async (id: string, update: any) => {
            const result = await updateGpi(tableName, id, mapToDb(update));
            return mapFromDb(result.data?.[0]);
        },
        findByIdAndDelete: async (id: string) => {
            await deleteGpi(tableName, id);
            return { id };
        },
        findOneAndDelete: async (query: any) => {
            const dbQuery = mapToDb(query);
            const existing = await findOneGpi(tableName, dbQuery);
            if (!existing) return null;
            await deleteGpi(tableName, existing.id);
            return mapFromDb(existing);
        },
        updateMany: async (query: any, update: any) => {
            const dbQuery = mapToDb(query);
            const dbUpdate = mapToDb(update.$set || update);
            let q = supabase.from(tableName).update(dbUpdate);
            Object.keys(dbQuery).forEach(key => {
                q = q.eq(key, dbQuery[key]);
            });
            const { error } = await q;
            if (error) throw error;
            return { acknowledged: true, modifiedCount: 0 };
        },
        deleteOne: async (query: any) => {
            const existing = await findOneGpi(tableName, mapToDb(query));
            if (!existing) return null;
            await deleteGpi(tableName, existing.id);
            return existing;
        },
        aggregate: (pipeline: any[]) => ({ toArray: async () => [] }),
        // For "new Model()" usage
        new: function(data: any) {
            const instance = { ...data };
            (instance as any).save = async () => {
                return await insertGpi(tableName, mapToDb(instance));
            };
            (instance as any).toObject = () => instance;
            return instance;
        }
    };
}

export const Project = createModel('projects');
export const Part = createModel('parts');
export const PaintingScheme = createModel('painting_schemes');
export const ApplicationRecord = createModel('application_records');
export const Inspection = createModel('inspections');
export const User = createModel('users');
export const Organization = createModel('organizations');
export const OrganizationMember = createModel('user_organizations');
export const StockItem = createModel('stock_items');
export const StockMovement = createModel('stock_movements');
export const StockAuditLog = createModel('stock_audit_logs');
export const Instrument = createModel('instruments');
export const TechnicalDataSheet = createModel('technical_data_sheets');
export const SystemSettings = createModel('system_settings');
export const Notification = createModel('notifications');
export const Message = createModel('messages');
export const GeometryType = createModel('geometry_types');
export const YieldStudy = createModel('yield_studies');
export const StoredFile = createModel('stored_files');

export { queryGpi, findOneGpi, insertGpi, updateGpi, deleteGpi };
