// Saloniq — Firebase client
// Initializes Firebase + exposes async helpers for the rest of the app.
//
// All security is enforced server-side via firestore.rules — the helpers here
// are convenience wrappers, not security boundaries.

(function initFirebase() {
  if (firebase.apps.length === 0) {
    firebase.initializeApp(window.SALONIQ_FIREBASE_CONFIG);
  }
})();

const fbAuth = firebase.auth();
const fbDb = firebase.firestore();

// Persist sessions across browser restarts (default is LOCAL but be explicit)
fbAuth.setPersistence(firebase.auth.Auth.Persistence.LOCAL).catch(() => {});

// Enable Firestore IndexedDB offline cache — survives reloads + computer crashes.
// Writes are queued locally if offline and replayed when network returns.
try {
  fbDb.enablePersistence({ synchronizeTabs: true }).catch(err => {
    if (err.code !== 'failed-precondition' && err.code !== 'unimplemented') {
      console.warn('Firestore persistence:', err.code, err.message);
    }
  });
} catch (e) { /* called twice or unsupported — safe to ignore */ }

// ─── Helpers ───────────────────────────────────────────────────────────────
const isSuperAdminEmail = (email) =>
  !!email && (window.SALONIQ_SUPER_ADMIN_EMAILS || []).includes(email.toLowerCase());

// Subscribe to auth-state changes; resolves user + their /users/{uid} profile.
function onAuthChange(callback) {
  return fbAuth.onAuthStateChanged(async (user) => {
    if (!user) {
      callback({ user: null, profile: null, isSuperAdmin: false });
      return;
    }
    const superAdmin = isSuperAdminEmail(user.email);
    let profile = null;
    if (!superAdmin) {
      try {
        const doc = await fbDb.collection('users').doc(user.uid).get();
        profile = doc.exists ? { id: doc.id, ...doc.data() } : null;
      } catch (e) {
        console.warn('Failed to load user profile', e);
      }
    }
    callback({ user, profile, isSuperAdmin: superAdmin });
  });
}

// ─── Auth ──────────────────────────────────────────────────────────────────
async function signIn(email, password, { remember = true } = {}) {
  // LOCAL = persists across browser restarts; SESSION = only this tab
  const persistence = remember
    ? firebase.auth.Auth.Persistence.LOCAL
    : firebase.auth.Auth.Persistence.SESSION;
  await fbAuth.setPersistence(persistence);
  return fbAuth.signInWithEmailAndPassword(email.trim().toLowerCase(), password);
}

async function signOut() {
  return fbAuth.signOut();
}

// Send password-reset email. Firebase generates a one-time link to its hosted
// reset page (or your custom continueUrl). Returns silently — we don't reveal
// whether the email exists, to avoid leaking which accounts are valid.
async function sendPasswordReset(email) {
  const cleanEmail = (email || '').trim().toLowerCase();
  if (!cleanEmail.includes('@')) throw new Error('Ugyldig email');
  return fbAuth.sendPasswordResetEmail(cleanEmail, {
    url: window.location.origin + '/?reset=done',
    handleCodeInApp: false,
  });
}

// ─── Salon directory ───────────────────────────────────────────────────────
async function listSalons() {
  const snap = await fbDb.collection('salons').orderBy('createdAt', 'desc').get();
  return snap.docs.map(d => ({ id: d.id, ...d.data() }));
}

async function getSalonBySubdomain(subdomain) {
  const snap = await fbDb.collection('salons')
    .where('subdomain', '==', subdomain.toLowerCase())
    .limit(1).get();
  if (snap.empty) return null;
  const doc = snap.docs[0];
  return { id: doc.id, ...doc.data() };
}

async function getSalon(salonId) {
  const doc = await fbDb.collection('salons').doc(salonId).get();
  return doc.exists ? { id: doc.id, ...doc.data() } : null;
}

// ─── Super-admin operations ────────────────────────────────────────────────
// Creates: 1) Firebase Auth user (in a SECONDARY auth instance so we don't
// kick out the super-admin), 2) /users/{uid} profile, 3) /salons/{salonId} doc.
async function createSalonWithOwner({ salonName, subdomain, color, ownerEmail, ownerPassword, ownerName }) {
  const cleanSubdomain = subdomain.toLowerCase().replace(/[^a-z0-9-]/g, '');
  const cleanEmail = ownerEmail.trim().toLowerCase();
  if (!cleanSubdomain) throw new Error('Ugyldigt subdomæne');
  if (!cleanEmail.includes('@')) throw new Error('Ugyldig email');
  if (!ownerPassword || ownerPassword.length < 6) throw new Error('Adgangskode skal være mindst 6 tegn');

  // Check subdomain isn't taken
  const existing = await getSalonBySubdomain(cleanSubdomain);
  if (existing) throw new Error('Subdomænet er allerede i brug');

  // Use a secondary auth instance so super-admin doesn't get signed out
  const secondaryAppName = '__secondary_' + Date.now();
  const secondaryApp = firebase.initializeApp(window.SALONIQ_FIREBASE_CONFIG, secondaryAppName);
  let cred;
  try {
    cred = await secondaryApp.auth().createUserWithEmailAndPassword(cleanEmail, ownerPassword);
  } finally {
    await secondaryApp.delete();
  }

  const uid = cred.user.uid;
  const salonId = cleanSubdomain;
  const now = firebase.firestore.FieldValue.serverTimestamp();

  // Create /salons/{salonId} + /users/{uid} in a batch
  const batch = fbDb.batch();
  batch.set(fbDb.collection('salons').doc(salonId), {
    name: salonName,
    subdomain: cleanSubdomain,
    color: color || '#3F4A3A',
    active: true,
    createdAt: now,
    createdBy: fbAuth.currentUser?.uid || 'super-admin',
  });
  batch.set(fbDb.collection('users').doc(uid), {
    email: cleanEmail,
    salonId,
    role: 'owner',
    name: ownerName || cleanEmail,
    createdAt: now,
  });
  await batch.commit();

  return { salonId, uid };
}

async function setSalonActive(salonId, active) {
  await fbDb.collection('salons').doc(salonId).update({ active });
}

async function updateSalon(salonId, patch) {
  await fbDb.collection('salons').doc(salonId).update(patch);
}

// Reset salon's adminPin (clear it). Owner is prompted to set a new PIN
// on next login via PinSetupModal. Operates on the private state doc.
async function resetSalonPin(salonId) {
  const ref = fbDb.collection('salons').doc(salonId).collection('private').doc('state');
  const doc = await ref.get();
  if (!doc.exists) return;
  const data = doc.data();
  const settings = { ...(data.appSettings || {}), adminPin: '' };
  await ref.update({ appSettings: settings, updatedAt: firebase.firestore.FieldValue.serverTimestamp() });
}

async function deleteSalon(salonId) {
  // Delete /salons/{salonId} doc — full cascade requires a Cloud Function or manual cleanup.
  // For now we mark as inactive; super-admin can hard-delete the auth user from Firebase Console.
  await fbDb.collection('salons').doc(salonId).delete();
}

async function listSalonUsers(salonId) {
  const snap = await fbDb.collection('users').where('salonId', '==', salonId).get();
  return snap.docs.map(d => ({ id: d.id, ...d.data() }));
}

async function addSalonUser({ salonId, email, password, name, role }) {
  const cleanEmail = email.trim().toLowerCase();
  if (!cleanEmail.includes('@')) throw new Error('Ugyldig email');
  if (!password || password.length < 6) throw new Error('Adgangskode skal være mindst 6 tegn');

  const secondaryAppName = '__secondary_' + Date.now();
  const secondaryApp = firebase.initializeApp(window.SALONIQ_FIREBASE_CONFIG, secondaryAppName);
  let cred;
  try {
    cred = await secondaryApp.auth().createUserWithEmailAndPassword(cleanEmail, password);
  } finally {
    await secondaryApp.delete();
  }

  await fbDb.collection('users').doc(cred.user.uid).set({
    email: cleanEmail,
    salonId,
    role: role || 'staff',
    name: name || cleanEmail,
    createdAt: firebase.firestore.FieldValue.serverTimestamp(),
  });
  return cred.user.uid;
}

async function removeSalonUser(uid) {
  // Removes Firestore profile only; the auth user must be deleted from Firebase
  // Console (or via a Cloud Function) for full cleanup.
  await fbDb.collection('users').doc(uid).delete();
}

// Map common Firebase auth-error codes to Danish user-friendly messages
function authErrorMessage(err) {
  const code = err?.code || '';
  if (code === 'auth/wrong-password' || code === 'auth/invalid-credential' || code === 'auth/user-not-found' || code === 'auth/invalid-login-credentials')
    return 'Forkert email eller adgangskode.';
  if (code === 'auth/too-many-requests')
    return 'For mange forsøg. Vent et øjeblik og prøv igen.';
  if (code === 'auth/email-already-in-use')
    return 'Denne email er allerede brugt af en anden konto.';
  if (code === 'auth/network-request-failed')
    return 'Ingen forbindelse til serveren. Tjek dit netværk og prøv igen.';
  if (code === 'auth/weak-password')
    return 'Adgangskoden er for svag. Brug mindst 6 tegn.';
  if (code === 'auth/invalid-email')
    return 'Ugyldig email-adresse.';
  return err?.message || 'Der skete en fejl. Prøv igen.';
}

// ─── Image helper ─────────────────────────────────────────────────────────────
// Resize and re-encode an uploaded image to a small JPEG dataURL so it fits
// inside a Firestore document. Without this, full-resolution iPhone photos
// (~4MB base64) would push the salon doc over Firestore's 1MB hard cap and
// fail every subsequent save silently — the cause of "data doesn't persist"
// reports.
window.SaloniqResizeImage = function (file, maxDim = 400, quality = 0.78) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onerror = () => reject(new Error('Kunne ikke læse fil'));
    reader.onload = (ev) => {
      const img = new Image();
      img.onerror = () => reject(new Error('Ugyldigt billedformat'));
      img.onload = () => {
        const ratio = Math.min(maxDim / img.width, maxDim / img.height, 1);
        const w = Math.round(img.width * ratio);
        const h = Math.round(img.height * ratio);
        const canvas = document.createElement('canvas');
        canvas.width = w; canvas.height = h;
        const ctx = canvas.getContext('2d');
        ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, w, h); // flatten transparency
        ctx.drawImage(img, 0, 0, w, h);
        // SVG goes through as-is (canvas can't faithfully rasterize them anyway).
        if (file.type === 'image/svg+xml') resolve(ev.target.result);
        else resolve(canvas.toDataURL('image/jpeg', quality));
      };
      img.src = ev.target.result;
    };
    reader.readAsDataURL(file);
  });
};

window.SaloniqFirebase = {
  auth: fbAuth, db: fbDb,
  isSuperAdminEmail, onAuthChange,
  signIn, signOut, sendPasswordReset,
  listSalons, getSalonBySubdomain, getSalon,
  createSalonWithOwner, setSalonActive, deleteSalon, updateSalon, resetSalonPin,
  listSalonUsers, addSalonUser, removeSalonUser,
  authErrorMessage,
};

// ─── Per-salon data store ─────────────────────────────────────────────────────
// Backed by Firestore — works across devices, survives crashes via IndexedDB
// offline cache. Single doc per salon at /salons/{id}/private/state.
//
// One-time migration: if Firestore has no doc yet but localStorage does (from
// the previous localStorage-only build), upload the localStorage data and clear it.
function _privateRef(salonId) {
  return fbDb.collection('salons').doc(salonId).collection('private').doc('state');
}

async function _migrateLegacyLocal(salonId) {
  try {
    const raw = localStorage.getItem('saloniq_data_' + salonId);
    if (!raw) return null;
    const data = JSON.parse(raw);
    await _privateRef(salonId).set({
      ...data,
      _migratedFromLocalStorage: true,
      updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
    });
    localStorage.removeItem('saloniq_data_' + salonId);
    return data;
  } catch {
    return null;
  }
}

window.SaloniqSalonData = {
  // Load salon's full state. Returns Promise<data | null>.
  async load(salonId) {
    if (!salonId) return null;
    try {
      const doc = await _privateRef(salonId).get();
      if (doc.exists) return doc.data();
      // First-time load — try migrating from localStorage if present
      return await _migrateLegacyLocal(salonId);
    } catch (e) {
      console.error('Failed to load salon data', e);
      return null;
    }
  },

  // Save full state. Firestore overwrites the doc; offline writes queue.
  async save(salonId, data) {
    if (!salonId) return;
    try {
      // Firestore can't store undefined; sanitize via JSON round-trip
      const clean = JSON.parse(JSON.stringify(data || {}));
      clean.updatedAt = firebase.firestore.FieldValue.serverTimestamp();
      await _privateRef(salonId).set(clean);
    } catch (e) {
      console.error('Failed to save salon data', e);
      // Surface to the user so they know something went wrong instead of
      // assuming changes are saved. Common case: doc-too-large from raw photos.
      const msg = e?.message?.includes('exceeds the maximum')
        ? 'Kunne ikke gemme — billede eller anden data fylder for meget. Prøv et mindre billede.'
        : 'Kunne ikke gemme ændringer (' + (e?.code || 'fejl') + '). Tjek netværket og prøv igen.';
      window.dispatchEvent(new CustomEvent('saloniq-save-error', { detail: msg }));
    }
  },

  // Real-time subscription — fires whenever another device updates the doc.
  // Returns unsubscribe function.
  subscribe(salonId, callback) {
    if (!salonId) return () => {};
    return _privateRef(salonId).onSnapshot(
      doc => { if (doc.exists) callback(doc.data()); },
      err => console.warn('Salon data subscription error:', err),
    );
  },
};
