// ============================================================
// SUPABASE CLIENT — Nomerus_site
// ============================================================
// Le client est exposé sur window.nomerusSb et window.nomerusAuth pour
// être consommé par auth.jsx, dashboard.jsx et index.html sans avoir à
// passer par un système de modules (rappel : le site est compilé par
// Babel standalone au runtime, sans bundler).
//
// La clé anon est publique par design — elle est protégée côté serveur
// par les Row-Level Security policies (table profiles, trades, subscriptions).
// L'URL et la clé sont les mêmes que dans le .env de l'app desktop.

const NOMERUS_SUPABASE_URL = "https://ctrbtvqogntpkrkwajvn.supabase.co";
const NOMERUS_SUPABASE_ANON_KEY =
  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." +
  "eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImN0cmJ0dnFvZ250cGtya3dhanZuIiwicm9sZSI6ImFub24i" +
  "LCJpYXQiOjE3NzgwNzAxNjIsImV4cCI6MjA5MzY0NjE2Mn0." +
  "68ty4vYZ7kQQ7LNsS5Fp0nl2PFLsrow5obuKbtGE8IA";

// `window.supabase` est exposé par le bundle UMD CDN @supabase/supabase-js@2.
// On le wrap pour ne pas planter si le CDN n'a pas encore chargé.
const _createClient = () => {
  if (!window.supabase || !window.supabase.createClient) {
    console.warn("[supabase] CDN supabase-js pas encore chargé");
    return null;
  }
  return window.supabase.createClient(
    NOMERUS_SUPABASE_URL,
    NOMERUS_SUPABASE_ANON_KEY,
    {
      auth: {
        persistSession: true,
        autoRefreshToken: true,
        detectSessionInUrl: true,
        flowType: "pkce",
      },
    },
  );
};

let _client = _createClient();
const nomerusSb = () => {
  if (_client) return _client;
  _client = _createClient();
  return _client;
};

// ── Auth helpers (utilisés par auth.jsx) ──────────────────────────────────
const nomerusAuth = {
  async signInPassword(email, password) {
    const sb = nomerusSb();
    if (!sb) throw new Error("Supabase indisponible.");
    const { data, error } = await sb.auth.signInWithPassword({ email, password });
    if (error) throw error;
    return data;
  },

  async signUpPassword(email, password, displayName) {
    const sb = nomerusSb();
    if (!sb) throw new Error("Supabase indisponible.");
    const { data, error } = await sb.auth.signUp({
      email,
      password,
      options: { data: { display_name: displayName } },
    });
    if (error) throw error;
    return data;
  },

  async signInGoogle() {
    const sb = nomerusSb();
    if (!sb) throw new Error("Supabase indisponible.");
    // redirectTo doit pointer vers la page elle-même : après le retour
    // de Google → Supabase, on revient ici, detectSessionInUrl écrit la
    // session, et onAuthStateChange déclenche le passage au dashboard.
    const redirectTo = window.location.origin + window.location.pathname;
    const { data, error } = await sb.auth.signInWithOAuth({
      provider: "google",
      options: { redirectTo },
    });
    if (error) throw error;
    return data;
  },

  async resetPassword(email) {
    const sb = nomerusSb();
    if (!sb) throw new Error("Supabase indisponible.");
    // Le lien email ramène sur l'écran de saisie du nouveau mot de passe.
    // (⚠ l'URL doit être dans la Redirect Allow List du Dashboard Supabase)
    const redirectTo = window.location.origin + "/reset-password";
    const { data, error } = await sb.auth.resetPasswordForEmail(email, { redirectTo });
    if (error) throw error;
    return data;
  },

  /** Change le mot de passe de l'utilisateur connecté (fin du flux recovery). */
  async updatePassword(newPassword) {
    const sb = nomerusSb();
    if (!sb) throw new Error("Supabase indisponible.");
    const { data, error } = await sb.auth.updateUser({ password: newPassword });
    if (error) throw error;
    return data;
  },

  async signOut() {
    const sb = nomerusSb();
    if (!sb) return;
    await sb.auth.signOut();
  },

  async getSession() {
    const sb = nomerusSb();
    if (!sb) return null;
    const { data } = await sb.auth.getSession();
    return data.session;
  },

  onAuthStateChange(cb) {
    const sb = nomerusSb();
    if (!sb) return () => {};
    // L'event est passé en 2e argument (les abonnés existants qui ne lisent
    // que la session ne sont pas impactés). Nécessaire pour PASSWORD_RECOVERY.
    const { data } = sb.auth.onAuthStateChange((event, session) => cb(session, event));
    return () => {
      try { data.subscription.unsubscribe(); } catch (e) {}
    };
  },

  // ── Traduction d'erreurs Supabase → FR user-friendly ───────────────────
  errorToFr(err) {
    const raw = (err && (err.message || err.error_description || String(err))) || "Erreur inconnue.";
    const m = raw.toLowerCase();
    if (m.includes("invalid login") || m.includes("invalid credentials"))
      return "Email ou mot de passe incorrect.";
    if (m.includes("email not confirmed"))
      return "Email non confirmé. Vérifie ta boîte mail.";
    if (m.includes("user already registered") || m.includes("already registered"))
      return "Un compte existe déjà avec cet email.";
    if (m.includes("password") && (m.includes("short") || m.includes("characters")))
      return "Mot de passe trop court (8 caractères minimum).";
    if (m.includes("rate") || m.includes("too many"))
      return "Trop de tentatives. Réessaie dans quelques minutes.";
    if (m.includes("network") || m.includes("fetch"))
      return "Connexion réseau impossible.";
    return raw;
  },
};

// ── Data helpers (utilisés par dashboard) ─────────────────────────────────
const nomerusData = {
  /** Renvoie les N derniers trades de l'utilisateur courant (ordre desc par date). */
  async recentTrades(limit = 10) {
    const sb = nomerusSb();
    if (!sb) return [];
    const { data, error } = await sb
      .from("trades")
      .select("id, date, asset, direction, entry_price, exit_price, pnl, r_multiple, result, strategy, session, platform, account, volume")
      .order("date", { ascending: false })
      .limit(limit);
    if (error) {
      console.warn("[supabase] recentTrades:", error);
      return [];
    }
    return data || [];
  },

  /** Calcule les KPIs depuis l'ensemble des trades de l'utilisateur. */
  async kpis() {
    const sb = nomerusSb();
    if (!sb) return null;
    const { data, error } = await sb
      .from("trades")
      .select("date, pnl, r_multiple, result")
      .order("date", { ascending: true });
    if (error) {
      console.warn("[supabase] kpis:", error);
      return null;
    }
    const trades = data || [];

    const now = new Date();
    const startToday = new Date(now); startToday.setHours(0, 0, 0, 0);
    const start30d = new Date(now.getTime() - 30 * 86400 * 1000);

    let equity = 0, pnlToday = 0, pnl30d = 0;
    let win30d = 0, count30d = 0;
    let peak = 0, maxDd = 0, maxDdPct = 0;
    const curve = [];

    for (const t of trades) {
      const pnl = Number(t.pnl) || 0;
      equity += pnl;
      curve.push(equity);
      peak = Math.max(peak, equity);
      const dd = equity - peak;
      if (dd < maxDd) maxDd = dd;
      // Drawdown en % relatif au pic courant (dd = (creux - pic) / pic)
      if (peak > 0) {
        const ddPct = (dd / peak) * 100;
        if (ddPct < maxDdPct) maxDdPct = ddPct;
      }
      const d = new Date(t.date);
      if (d >= startToday) pnlToday += pnl;
      if (d >= start30d) {
        pnl30d += pnl;
        count30d += 1;
        if ((t.result || "").toUpperCase() === "WIN") win30d += 1;
      }
    }

    const winRate = count30d > 0 ? (win30d / count30d) * 100 : 0;

    return {
      equity,
      pnlToday,
      pnl30d,
      maxDd,
      maxDdPct,
      winRate,
      nbTrades30d: count30d,
      nbTradesAll: trades.length,
      curve,
    };
  },

  /** Profil utilisateur (capital, max_risk, etc.). */
  async profile() {
    const sb = nomerusSb();
    if (!sb) return null;
    const { data } = await sb.from("profiles").select("*").maybeSingle();
    return data;
  },

  /** Abonnement (plan, status). */
  async subscription() {
    const sb = nomerusSb();
    if (!sb) return null;
    const { data } = await sb.from("subscriptions").select("plan, status, current_period_end").maybeSingle();
    return data;
  },
};

// ── Waitlist helper (utilisé par WWaitlist sur la landing) ───────────────
// La table `public.waitlist` a une policy RLS qui autorise INSERT anon.
// On capture automatiquement source/utm/referrer/user_agent depuis le
// contexte navigateur pour pouvoir attribuer les signups plus tard.
const nomerusWaitlist = {
  /**
   * Inscrit un email à la waitlist. Retourne { ok: true } en cas de succès,
   * { ok: false, error: "fr message" } en cas d'erreur.
   * @param {string} email
   */
  async join(email) {
    const sb = nomerusSb();
    if (!sb) return { ok: false, error: "Connexion Supabase indisponible." };

    const trimmed = (email || "").trim();
    if (!trimmed) return { ok: false, error: "Email requis." };

    // Lecture des UTM et du referrer au moment du submit (l'utilisateur a
    // pu naviguer entre temps, mais window.location reste cohérent puisque
    // le site est une SPA mono-document).
    const params = new URLSearchParams(window.location.search);
    const row = {
      email: trimmed,
      source:       params.get("source")       || "",
      utm_source:   params.get("utm_source")   || "",
      utm_medium:   params.get("utm_medium")   || "",
      utm_campaign: params.get("utm_campaign") || "",
      referrer:     (document.referrer || "").slice(0, 500),
      user_agent:   (navigator.userAgent || "").slice(0, 500),
    };

    const { error } = await sb.from("waitlist").insert(row);
    if (error) {
      const fr = nomerusWaitlist._errorToFr(error);
      return { ok: false, error: fr, _raw: error };
    }
    return { ok: true };
  },

  // Traduction des erreurs Supabase / Postgres en messages user-friendly.
  _errorToFr(err) {
    const raw = (err && (err.message || String(err))) || "";
    const m = raw.toLowerCase();
    if (m.includes("duplicate key") || m.includes("unique"))
      return "Cet email est déjà sur la liste. Tu seras prévenu(e) au lancement.";
    if (m.includes("waitlist_email_format_check") || (m.includes("check constraint") && m.includes("email")))
      return "Format d'email invalide.";
    if (m.includes("rate") || m.includes("too many"))
      return "Trop de tentatives. Réessaie dans quelques minutes.";
    if (m.includes("network") || m.includes("fetch"))
      return "Connexion réseau impossible.";
    return "Une erreur est survenue. Réessaie dans quelques instants.";
  },
};

// ── Contact helper (utilisé par WContact sur /contact) ───────────────────
// La table `public.contact_messages` a une policy RLS qui autorise INSERT
// anon (comme la waitlist) et aucune policy SELECT : les messages ne sont
// lisibles que depuis le Dashboard Supabase.
const nomerusContact = {
  /**
   * Envoie un message de contact. Retourne { ok: true } en cas de succès,
   * { ok: false, error: "message fr" } en cas d'erreur.
   * @param {{ name: string, email: string, topic: string, message: string }} payload
   */
  async send({ name, email, topic, message }) {
    const sb = nomerusSb();
    if (!sb) return { ok: false, error: "Connexion Supabase indisponible." };

    const row = {
      name:       (name || "").trim().slice(0, 120),
      email:      (email || "").trim(),
      topic:      topic || "general",
      message:    (message || "").trim().slice(0, 4000),
      page:       (document.referrer || "").slice(0, 300),
      user_agent: (navigator.userAgent || "").slice(0, 500),
    };
    if (!row.email) return { ok: false, error: "Email requis." };
    if (row.message.length < 10) return { ok: false, error: "Ton message est un peu court — décris ta demande en quelques mots de plus." };

    const { error } = await sb.from("contact_messages").insert(row);
    if (error) return { ok: false, error: nomerusContact._errorToFr(error), _raw: error };
    return { ok: true };
  },

  _errorToFr(err) {
    const raw = (err && (err.message || String(err))) || "";
    const m = raw.toLowerCase();
    if (m.includes("contact_email_format_check") || (m.includes("check constraint") && m.includes("email")))
      return "Format d'email invalide.";
    if (m.includes("contact_message_len_check"))
      return "Message trop court ou trop long (10 à 4000 caractères).";
    if (m.includes("rate") || m.includes("too many"))
      return "Trop de tentatives. Réessaie dans quelques minutes.";
    if (m.includes("network") || m.includes("fetch"))
      return "Connexion réseau impossible.";
    return "Une erreur est survenue. Réessaie dans quelques instants, ou écris-nous directement par email.";
  },
};

// ── News helper (Le Brief, page publique /news) ──────────────────────────
// Lecture seule : la table `public.news_posts` n'expose en RLS que les
// posts `published` en SELECT anon. L'écriture est réservée à l'Edge
// Function news-writer (service_role).
const nomerusNews = {
  /** Liste des derniers briefs publiés (métadonnées, sans le corps). */
  async list(limit = 30) {
    const sb = nomerusSb();
    if (!sb) return { ok: false, error: "Connexion Supabase indisponible.", posts: [] };
    const { data, error } = await sb
      .from("news_posts")
      .select("slug, title, hook, category, created_at")
      .order("created_at", { ascending: false })
      .limit(limit);
    if (error) return { ok: false, error: "Impossible de charger les briefs.", posts: [], _raw: error };
    return { ok: true, posts: data || [] };
  },

  /** Un brief complet par slug (vue article). */
  async get(slug) {
    const sb = nomerusSb();
    if (!sb || !slug) return { ok: false, error: "Brief introuvable.", post: null };
    const { data, error } = await sb
      .from("news_posts")
      .select("slug, title, hook, body_md, category, sources, model, created_at")
      .eq("slug", slug)
      .maybeSingle();
    if (error || !data) return { ok: false, error: "Brief introuvable.", post: null, _raw: error };
    return { ok: true, post: data };
  },
};

window.nomerusSb = nomerusSb;
window.NOMERUS_SUPABASE_URL = NOMERUS_SUPABASE_URL;
window.nomerusAuth = nomerusAuth;
window.nomerusData = nomerusData;
window.nomerusWaitlist = nomerusWaitlist;
window.nomerusContact = nomerusContact;
window.nomerusNews = nomerusNews;
