/**
 * HOA LedgerIQ — Lead Capture Backend
 * Stack: Node.js + Express + better-sqlite3
 *
 * Start: node server.js
 * Leads DB: ./data/leads.db
 */

'use strict';

require('dotenv').config();

const path    = require('path');
const fs      = require('fs');
const express = require('express');
const Database = require('better-sqlite3');
const OpenAI   = require('openai');

// ── Config ──────────────────────────────────────────────
const PORT    = process.env.PORT || 3000;

// ── AI client (OpenAI-compatible) ────────────────────────
const AI_API_URL = process.env.AI_API_URL || 'https://api.openai.com/v1';
const AI_API_KEY = process.env.AI_API_KEY || '';
const AI_MODEL   = process.env.AI_MODEL   || 'gpt-4o-mini';
const AI_DEBUG   = process.env.AI_DEBUG   === 'true';

const aiClient = AI_API_KEY
  ? new OpenAI({ apiKey: AI_API_KEY, baseURL: AI_API_URL })
  : null;
const DB_DIR  = path.join(__dirname, 'data');
const DB_PATH = path.join(DB_DIR, 'leads.db');

// ── DB setup ─────────────────────────────────────────────
fs.mkdirSync(DB_DIR, { recursive: true });

const db = new Database(DB_PATH);
db.pragma('journal_mode = WAL');

db.exec(`
  CREATE TABLE IF NOT EXISTS leads (
    id             INTEGER PRIMARY KEY AUTOINCREMENT,
    first_name     TEXT    NOT NULL,
    last_name      TEXT    NOT NULL,
    email          TEXT    NOT NULL UNIQUE,
    org_name       TEXT,
    state          TEXT,
    role           TEXT,
    unit_count     TEXT,
    beta_interest  INTEGER DEFAULT 0,
    source         TEXT    DEFAULT 'landing_page',
    created_at     TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
  );
`);

db.exec(`
  CREATE TABLE IF NOT EXISTS calc_submissions (
    id                INTEGER PRIMARY KEY AUTOINCREMENT,
    email             TEXT,
    opt_in            INTEGER DEFAULT 1,
    homesites         REAL,
    property_type     TEXT,
    annual_income     REAL,
    payment_freq      TEXT,
    reserve_funds     REAL,
    interest_2025     REAL,
    total_potential   REAL,
    op_interest       REAL,
    res_interest      REAL,
    ai_recommendation TEXT,
    created_at        TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
  );
`);

// Migrate existing DBs: add new columns if they don't exist yet
const cols = db.pragma('table_info(leads)').map(c => c.name);
if (!cols.includes('org_name'))      db.exec('ALTER TABLE leads ADD COLUMN org_name TEXT');
if (!cols.includes('state'))         db.exec('ALTER TABLE leads ADD COLUMN state TEXT');
if (!cols.includes('beta_interest')) db.exec('ALTER TABLE leads ADD COLUMN beta_interest INTEGER DEFAULT 0');

// Prepared statements
const insertLead = db.prepare(`
  INSERT INTO leads (first_name, last_name, email, org_name, state, role, unit_count, beta_interest, source)
  VALUES (@firstName, @lastName, @email, @orgName, @state, @role, @unitCount, @betaInterest, @source)
`);

const findByEmail = db.prepare(`SELECT id FROM leads WHERE email = ? LIMIT 1`);

const insertCalcSubmission = db.prepare(`
  INSERT INTO calc_submissions
    (email, opt_in, homesites, property_type, annual_income, payment_freq,
     reserve_funds, interest_2025, total_potential, op_interest, res_interest, ai_recommendation)
  VALUES
    (@email, @optIn, @homesites, @propertyType, @annualIncome, @paymentFreq,
     @reserveFunds, @interest2025, @totalPotential, @opInterest, @resInterest, @aiRecommendation)
`);

const getAllCalcSubmissions = db.prepare(`
  SELECT * FROM calc_submissions ORDER BY created_at DESC
`);

const getAllLeads = db.prepare(`
  SELECT id, first_name, last_name, email, org_name, state, role, unit_count, beta_interest, source, created_at
  FROM leads
  ORDER BY created_at DESC
`);

// ── App ───────────────────────────────────────────────────
const app = express();
app.use(express.json());
app.use(express.static(__dirname));   // serve the marketing site

// POST /api/leads  — capture a new preview sign-up
app.post('/api/leads', (req, res) => {
  const { firstName, lastName, email, orgName, state, role, unitCount, betaInterest, source } = req.body ?? {};

  // Validate required fields
  if (!firstName?.trim() || !lastName?.trim() || !email?.trim()) {
    return res.status(400).json({ error: 'firstName, lastName, and email are required.' });
  }
  if (!orgName?.trim()) {
    return res.status(400).json({ error: 'Organization name is required.' });
  }
  if (!state?.trim()) {
    return res.status(400).json({ error: 'State is required.' });
  }

  // Simple email format check
  const emailRx = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRx.test(email.trim())) {
    return res.status(400).json({ error: 'Invalid email address.' });
  }

  // Check for duplicate
  const existing = findByEmail.get(email.trim().toLowerCase());
  if (existing) {
    return res.status(409).json({ error: 'This email is already on the list.', id: existing.id });
  }

  try {
    const info = insertLead.run({
      firstName:    firstName.trim(),
      lastName:     lastName.trim(),
      email:        email.trim().toLowerCase(),
      orgName:      orgName?.trim() ?? null,
      state:        state?.trim() ?? null,
      role:         role ?? null,
      unitCount:    unitCount ?? null,
      betaInterest: betaInterest ? 1 : 0,
      source:       source ?? 'landing_page',
    });

    return res.status(201).json({ success: true, id: info.lastInsertRowid });
  } catch (err) {
    if (err.code === 'SQLITE_CONSTRAINT_UNIQUE') {
      return res.status(409).json({ error: 'This email is already on the list.' });
    }
    console.error('DB error:', err);
    return res.status(500).json({ error: 'Internal server error.' });
  }
});

// GET /api/leads  — internal: list all leads (add auth before exposing publicly)
app.get('/api/leads', (req, res) => {
  const secret = req.headers['x-admin-key'];
  if (!secret || secret !== process.env.ADMIN_KEY) {
    return res.status(401).json({ error: 'Unauthorized.' });
  }
  const leads = getAllLeads.all();
  res.json({ count: leads.length, leads });
});

// POST /api/calculate  — AI-powered investment recommendation
app.post('/api/calculate', async (req, res) => {
  function saveCalcSubmission(aiRecommendation) {
    try {
      insertCalcSubmission.run({
        email:           email?.trim() || null,
        optIn:           optIn ? 1 : 0,
        homesites:       homesites || null,
        propertyType:    propertyType || null,
        annualIncome:    annualIncome || null,
        paymentFreq:     paymentFreq || null,
        reserveFunds:    reserveFunds || null,
        interest2025:    interest2025 || null,
        totalPotential:  totalPotential || null,
        opInterest:      opInterest || null,
        resInterest:     resInterest || null,
        aiRecommendation: aiRecommendation || null,
      });
    } catch (err) {
      console.error('Failed to save calc submission:', err.message);
    }
  }

  if (!aiClient) {
    saveCalcSubmission(null);
    return res.status(503).json({ error: 'AI service not configured.' });
  }

  const {
    homesites, propertyType, annualIncome, paymentFreq, reserveFunds, interest2025,
    email, optIn, totalPotential, opInterest, resInterest,
  } = req.body ?? {};

  if (!homesites || !annualIncome) {
    return res.status(400).json({ error: 'homesites and annualIncome are required.' });
  }

  const fmt          = n => '$' + Math.round(n).toLocaleString();
  const typeLabel    = { sfh: 'single-family home', townhomes: 'townhome', condos: 'condo', mixed: 'mixed-use' }[propertyType] || '';
  const freqDivisor  = { monthly: 12, quarterly: 4, annually: 1 }[paymentFreq] || 12;
  const installmentAmt = annualIncome / freqDivisor;
  const freqDesc     = { monthly: 'monthly installments', quarterly: 'quarterly installments', annually: 'one lump-sum annual payment' }[paymentFreq] || 'monthly installments';

  const prompt = `You are a conservative HOA financial advisor. Given the following community data, provide a brief (3-4 sentence) plain-English investment income recommendation. Use only conservative, realistic estimates. Do not speculate beyond what the data supports.

Community: ${homesites}-unit ${typeLabel} association
Total annual dues income: ${fmt(annualIncome)} per year
Dues collection schedule: collected in ${freqDesc} of approximately ${fmt(installmentAmt)} per cycle (this affects operating cash flow timing, not the total annual amount)
Reserve fund balance: ${fmt(reserveFunds || 0)}
Interest income earned in 2025: ${fmt(interest2025 || 0)}

Provide a recommendation focused on:
1. How much of the reserve funds could conservatively be invested and in what vehicle (e.g. CD ladder, money market, T-bills)
2. How much operating cash float could earn interest between each collection cycle and upcoming expenses, given the ${freqDesc} schedule
3. A realistic estimated annual interest income potential based on the full ${fmt(annualIncome)} annual dues total
4. A single sentence comparing that to their 2025 actual if provided

Keep the tone professional and factual. No bullet points — flowing paragraph only.`;

  if (AI_DEBUG) {
    console.log('[AI_DEBUG] model:', AI_MODEL);
    console.log('[AI_DEBUG] prompt:', prompt);
  }

  try {
    const completion = await aiClient.chat.completions.create({
      model:      AI_MODEL,
      max_tokens: 300,
      messages:   [{ role: 'user', content: prompt }],
    });

    const text = completion.choices[0]?.message?.content ?? '';

    if (AI_DEBUG) console.log('[AI_DEBUG] response:', text);

    saveCalcSubmission(text);
    res.json({ recommendation: text });
  } catch (err) {
    console.error('AI API error:', err.message);
    saveCalcSubmission(null);
    res.status(502).json({ error: 'AI service unavailable. Showing estimated result.' });
  }
});

// GET /api/calc-submissions  — internal: list all calculator submissions
app.get('/api/calc-submissions', (req, res) => {
  const secret = req.headers['x-admin-key'];
  if (!secret || secret !== process.env.ADMIN_KEY) {
    return res.status(401).json({ error: 'Unauthorized.' });
  }
  const rows = getAllCalcSubmissions.all();
  res.json({ count: rows.length, submissions: rows });
});

// Health check
app.get('/api/health', (_req, res) => res.json({ status: 'ok', ts: new Date().toISOString() }));

// ── Start ─────────────────────────────────────────────────
app.listen(PORT, () => {
  console.log(`\n  HOA LedgerIQ server running at http://localhost:${PORT}`);
  console.log(`  Leads DB: ${DB_PATH}\n`);
});
