// pocketbase.js — Firebase-compatible PocketBase adapter
// Replace firebase.js with this file. All Firebase-using files work unchanged.
//
// Swap imports:
//   find . -name "*.js" -exec sed -i 's|from "./firebase.js"|from "./pocketbase.js"|g' {} +
//   find . -name "*.js" -exec sed -i 's|from "https://www\.gstatic\.com/firebasejs/...|from "./pocketbase.js"|g' {} +
//
// See firebase-to-pocketbase-migration skill for full migration guide.

import PocketBase from "https://cdn.jsdelivr.net/npm/pocketbase@0.21.5/dist/pocketbase.es.mjs";

// ─── PocketBase Init ───────────────────────────────────────────────
const BASE_URL = window.location.origin;
const pb = new PocketBase(BASE_URL);

// ─── Auth (Firebase-compatible surface) ────────────────────────────
const auth = {
    get currentUser() {
        if (!pb.authStore.isValid) return null;
        const model = pb.authStore.model;
        // Only return users from 'users' collection, not superusers/admins
        if (model.collectionName !== 'users') return null;
        return {
            uid: model.id,
            email: model.email,
            displayName: model.name || null
        };
    },

    onAuthStateChanged(callback) {
        // Fire initial state synchronously (like Firebase does)
        const current = this.currentUser;
        callback(current);

        // Listen for future auth changes
        pb.authStore.onChange((token, model) => {
            const user = (model && model.collectionName === 'users') ? {
                uid: model.id,
                email: model.email,
                displayName: model.name || null
            } : null;
            callback(user);
        });
        return () => {};
    }
};

// ─── Standalone Auth Functions ─────────────────────────────────────
function onAuthStateChanged(authRef, callback) { return auth.onAuthStateChanged(callback); }

async function signInWithEmailAndPassword(a, email, password) {
    await pb.collection('users').authWithPassword(email, password);
    return { user: auth.currentUser };
}

async function createUserWithEmailAndPassword(a, email, password) {
    await pb.collection('users').create({
        email, password, passwordConfirm: password, emailVisibility: true
    });
    await pb.collection('users').authWithPassword(email, password);
    return { user: auth.currentUser };
}

async function signOut(a) { pb.authStore.clear(); }

async function sendPasswordResetEmail(a, email) {
    await pb.collection('users').requestPasswordReset(email);
}

async function updateProfile(user, data) {
    const updateData = {};
    if (data.displayName) updateData.name = data.displayName;
    await pb.collection('users').update(user.uid, updateData);
    return { ...user, displayName: data.displayName || user.displayName };
}

async function updatePassword(user, newPassword) {
    await pb.collection('users').update(user.uid, {
        password: newPassword, passwordConfirm: newPassword
    });
}

async function reauthenticateWithCredential(user, credential) {
    await pb.collection('users').authWithPassword(credential._email, credential._password);
}

const EmailAuthProvider = {
    credential: (email, password) => ({ _email: email, _password: password })
};

// ─── Firestore-compatible DB Surface ───────────────────────────────
const db = {};

function collection(parent, name, ...subPath) {
    if (subPath.length === 0) {
        return { _type: 'collection', _name: name, _path: [name] };
    }
    const collectionName = subPath[subPath.length - 1];
    return { _type: 'collection', _name: collectionName, _path: [name, ...subPath], _userId: subPath[0] };
}

function doc(db, ...path) {
    if (path.length === 2) return { _type: 'doc', _collection: path[0], _id: path[1] };
    return { _type: 'doc', _collection: path[path.length - 2], _id: path[path.length - 1], _userId: path[1] };
}

// ─── Query Builder ─────────────────────────────────────────────────
function where(field, op, value) { return { _type: 'where', field, op, value }; }
function orderBy(field, direction) { return { _type: 'orderBy', field, direction }; }
function limit(n) { return { _type: 'limit', value: n }; }
function query(collRef, ...constraints) { return { _type: 'query', collection: collRef, constraints }; }

// ─── PocketBase Filter Builder ─────────────────────────────────────
const OP_MAP = {'==': '=', '!=': '!=', '>': '>', '<': '<', '>=': '>=', '<=': '<=', 'in': '?=', 'not-in': '?!='};

function buildFilter(constraints) {
    const parts = [];
    for (const c of constraints) {
        if (c._type !== 'where') continue;
        const pbOp = OP_MAP[c.op] || '=';
        if (pbOp === '?=' && Array.isArray(c.value)) {
            const orParts = c.value.map(v => typeof v === 'string' ? `${c.field} ?= "${v}"` : `${c.field} ?= ${v}`);
            parts.push(`(${orParts.join(' || ')})`);
        } else if (pbOp === '?=') {
            const v = typeof c.value === 'string' ? `"${c.value}"` : c.value;
            parts.push(`${c.field} ${pbOp} ${v}`);
        } else {
            const v = typeof c.value === 'string' ? `"${c.value}"` : c.value;
            parts.push(`${c.field} ${pbOp} ${v}`);
        }
    }
    return parts.length > 0 ? parts.join(' && ') : '';
}

function buildSort(constraints) {
    return constraints.filter(c => c._type === 'orderBy').map(c => (c.direction === 'desc' ? '-' : '+') + c.field);
}

// ─── CRUD Operations ───────────────────────────────────────────────
async function getDocs(q) {
    const collName = q.collection._name;
    const filter = buildFilter(q.constraints);
    const sort = buildSort(q.constraints);
    const limitVal = q.constraints.find(c => c._type === 'limit');
    const options = { requestKey: null };
    if (filter) options.filter = filter;
    if (sort.length > 0) options.sort = sort.join(',');
    if (limitVal) options.perPage = limitVal.value;

    try {
        const records = limitVal
            ? await pb.collection(collName).getList(1, limitVal.value, options)
            : await pb.collection(collName).getFullList(options);
        const items = limitVal ? records.items : records;

        const docs = items.map(rec => ({
            id: rec.id, data: () => convertFromPB(rec), exists: true, ref: { id: rec.id }
        }));
        docs.forEach = function(cb) { this.forEach(cb); };
        return docs;
    } catch (err) {
        console.warn(`PocketBase getDocs(${collName}):`, err.message);
        const empty = []; empty.forEach = function(cb) {}; return empty;
    }
}

async function addDoc(collRef, data) {
    const record = await pb.collection(collRef._name).create(convertToPB(data));
    return { id: record.id };
}

async function updateDoc(docRef, data) {
    await pb.collection(docRef._collection).update(docRef._id, convertToPB(data));
}

async function deleteDoc(docRef) {
    await pb.collection(docRef._collection).delete(docRef._id);
}

async function getDoc(docRef) {
    try {
        const record = await pb.collection(docRef._collection).getOne(docRef._id);
        return { id: record.id, data: () => convertFromPB(record), exists: true };
    } catch (err) { return { exists: false, data: () => null }; }
}

function setDoc(docRef, data) {
    const pbData = convertToPB(data);
    return pb.collection(docRef._collection).update(docRef._id, pbData).catch(() =>
        pb.collection(docRef._collection).create({ ...pbData, id: docRef._id })
    ).then(rec => ({ id: rec.id }));
}

function onSnapshot(queryOrDocRef, callback) {
    if (queryOrDocRef._type === 'query') {
        getDocs(queryOrDocRef).then(docs => callback({ docs, forEach: cb => docs.forEach(cb) }));
    } else {
        getDoc(queryOrDocRef).then(doc => callback(doc));
    }
    return () => {};
}

// ─── Timestamps ────────────────────────────────────────────────────
function serverTimestamp() { return new Date().toISOString(); }

class Timestamp {
    constructor(date) { this._date = date || new Date(); }
    toDate() { return this._date; }
    toMillis() { return this._date.getTime(); }
}

// ─── Data Conversion ───────────────────────────────────────────────
// Add your app's timestamp field names here
const TIMESTAMP_FIELDS = new Set([
    'writeupTime', 'createdAt', 'updatedAt', 'lastUpdated',
    'appointmentDateTime', 'completionTime', 'lastActivity',
    'timestamp', 'dateCreated', 'startDate', 'endDate', 'deadline'
]);

function convertToPB(data) {
    const result = {};
    for (const [key, value] of Object.entries(data)) {
        if (value === undefined) continue;
        if (value && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date)) {
            result[key] = JSON.stringify(value);
        } else if (value instanceof Date) {
            result[key] = value.toISOString();
        } else {
            result[key] = value;
        }
    }
    return result;
}

function convertFromPB(record) {
    const data = { ...record };
    for (const field of TIMESTAMP_FIELDS) {
        if (typeof data[field] === 'string' && data[field].match(/^\d{4}-\d{2}-\d{2}T/)) {
            data[field] = new Timestamp(new Date(data[field]));
        }
    }
    for (const [key, value] of Object.entries(data)) {
        if (typeof value === 'string' && (value.startsWith('{') || value.startsWith('['))) {
            try { const p = JSON.parse(value); if (typeof p === 'object') data[key] = p; } catch (e) {}
        }
    }
    return data;
}

// ─── Exports ───────────────────────────────────────────────────────
export { auth, db };
export {
    signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut,
    sendPasswordResetEmail, updateProfile, onAuthStateChanged,
    updatePassword, reauthenticateWithCredential, EmailAuthProvider
};
export {
    collection, doc, query, where, orderBy, limit,
    getDocs, getDoc, addDoc, updateDoc, deleteDoc, setDoc, onSnapshot,
    serverTimestamp, Timestamp
};
