import { Hono } from 'hono';
import { db, dbGet, dbAll, legalPages } from '../db/index.js';
import { eq, desc } from 'drizzle-orm';
import { requireAuth } from '../lib/auth.js';
import { getNow, generateId } from '../lib/utils.js';
import { replaceLegalPlaceholders } from '../lib/legal-placeholders.js';
import fs from 'fs';
import path from 'path';

const legalPagesRouter = new Hono();

// Helper: Convert markdown to plain text for editing
function markdownToText(markdown: string): string {
  if (!markdown) return '';
  
  let text = markdown;
  
  // Remove markdown heading markers (# ## ###)
  text = text.replace(/^#{1,6}\s+/gm, '');
  
  // Remove horizontal rules
  text = text.replace(/^---+$/gm, '');
  
  // Remove bold/italic markers
  text = text.replace(/\*\*([^*]+)\*\*/g, '$1');
  text = text.replace(/\*([^*]+)\*/g, '$1');
  text = text.replace(/__([^_]+)__/g, '$1');
  text = text.replace(/_([^_]+)_/g, '$1');
  
  // Remove list markers (preserve text)
  text = text.replace(/^\s*[\*\-\+]\s+/gm, '');
  text = text.replace(/^\s*\d+\.\s+/gm, '');
  
  // Remove link formatting [text](url) -> text
  text = text.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1');
  
  // Remove double-space line breaks
  text = text.replace(/  \n/g, '\n');
  
  // Normalize multiple newlines
  text = text.replace(/\n{3,}/g, '\n\n');
  
  return text.trim();
}

// Helper: Extract title from markdown content
function extractTitleFromMarkdown(content: string): string {
  if (!content) return 'Untitled';
  
  const match = content.match(/^#\s+(.+?)(?:\s*[–-]\s*.+)?$/m);
  if (match) {
    return match[1].trim();
  }
  // Fallback to first line
  const firstLine = content.split('\n')[0].replace(/^#+\s*/, '').trim();
  return firstLine || 'Untitled';
}

// Helper: Get legal directory path
function getLegalDir(): string {
  // When running from backend, legal folder is in frontend
  const possiblePaths = [
    path.join(process.cwd(), '../frontend/legal'),
    path.join(process.cwd(), 'frontend/legal'),
    path.join(process.cwd(), 'legal'),
  ];
  
  for (const p of possiblePaths) {
    if (fs.existsSync(p)) {
      return p;
    }
  }
  
  return possiblePaths[0]; // Default
}

// Helper: Convert filename to slug
function fileNameToSlug(fileName: string): string {
  return fileName.replace('.md', '').replace(/_/g, '-');
}

// Title map for localization
const titleMap: Record<string, { en: string; es: string }> = {
  'privacy-policy': { en: 'Privacy Policy', es: 'Política de Privacidad' },
  'terms-policy': { en: 'Terms & Conditions', es: 'Términos y Condiciones' },
  'refund-cancelation-policy': { en: 'Refund & Cancellation Policy', es: 'Política de Reembolso y Cancelación' },
};

// Helper: Get localized content with fallback
// If requested locale content is missing, fallback to the other locale
function getLocalizedContent(page: any, locale: string = 'en'): { title: string; contentMarkdown: string } {
  const isSpanish = locale === 'es';
  
  // Title: prefer requested locale, fallback to other
  let title: string;
  if (isSpanish) {
    title = page.titleEs || page.title;
  } else {
    title = page.title || page.titleEs;
  }
  
  // Content: prefer requested locale, fallback to other
  let contentMarkdown: string;
  if (isSpanish) {
    contentMarkdown = page.contentMarkdownEs || page.contentMarkdown;
  } else {
    contentMarkdown = page.contentMarkdown || page.contentMarkdownEs;
  }
  
  return { title, contentMarkdown };
}

// ==================== Public Routes ====================

// Get all legal pages (public, for footer/navigation)
legalPagesRouter.get('/', async (c) => {
  const locale = c.req.query('locale') || 'en';
  
  const pages = await dbAll<any>(
    (db as any)
      .select({
        id: (legalPages as any).id,
        slug: (legalPages as any).slug,
        title: (legalPages as any).title,
        titleEs: (legalPages as any).titleEs,
        updatedAt: (legalPages as any).updatedAt,
      })
      .from(legalPages)
      .orderBy((legalPages as any).slug)
  );
  
  // Return pages with localized title
  const localizedPages = pages.map((page: any) => ({
    id: page.id,
    slug: page.slug,
    title: locale === 'es' ? (page.titleEs || page.title) : (page.title || page.titleEs),
    updatedAt: page.updatedAt,
  }));
  
  return c.json({ pages: localizedPages });
});

// Get single legal page (public, for rendering)
legalPagesRouter.get('/:slug', async (c) => {
  const { slug } = c.req.param();
  const locale = c.req.query('locale') || 'en';

  // Reject anything that isn't a simple slug. The filesystem fallback below builds a
  // path from this value, so an unconstrained slug (e.g. "../../etc/passwd") would
  // allow path traversal / arbitrary file reads.
  if (!/^[a-z0-9-]+$/.test(slug)) {
    return c.json({ error: 'Legal page not found' }, 404);
  }
  
  // First try to get from database
  const page = await dbGet<any>(
    (db as any).select().from(legalPages).where(eq((legalPages as any).slug, slug))
  );
  
  if (page) {
    // Get localized content with fallback
    const { title, contentMarkdown } = getLocalizedContent(page, locale);
    
    // Replace legal placeholders before returning
    const processedContent = await replaceLegalPlaceholders(contentMarkdown, page.updatedAt);
    
    return c.json({
      page: {
        id: page.id,
        slug: page.slug,
        title,
        contentMarkdown: processedContent,
        updatedAt: page.updatedAt,
        source: 'database',
      }
    });
  }
  
  // Fallback to filesystem
  const legalDir = getLegalDir();
  const fileName = slug.replace(/-/g, '_') + '.md';
  const filePath = path.join(legalDir, fileName);
  
  if (fs.existsSync(filePath)) {
    const content = fs.readFileSync(filePath, 'utf-8');
    const titles = titleMap[slug];
    const title = locale === 'es' 
      ? (titles?.es || titles?.en || slug)
      : (titles?.en || titles?.es || slug);
    
    // Replace legal placeholders in filesystem content too
    const processedContent = await replaceLegalPlaceholders(content);
    
    return c.json({
      page: {
        slug,
        title,
        contentMarkdown: processedContent,
        source: 'filesystem',
      }
    });
  }
  
  return c.json({ error: 'Legal page not found' }, 404);
});

// ==================== Admin Routes ====================

// Get all legal pages for admin (with full content)
legalPagesRouter.get('/admin/list', requireAuth(['admin']), async (c) => {
  const pages = await dbAll<any>(
    (db as any)
      .select()
      .from(legalPages)
      .orderBy((legalPages as any).slug)
  );
  
  // Add flags to indicate which languages have content
  const pagesWithFlags = pages.map((page: any) => ({
    ...page,
    hasEnglish: Boolean(page.contentText),
    hasSpanish: Boolean(page.contentTextEs),
  }));
  
  return c.json({ pages: pagesWithFlags });
});

// Get single legal page for editing (admin)
legalPagesRouter.get('/admin/:slug', requireAuth(['admin']), async (c) => {
  const { slug } = c.req.param();
  
  const page = await dbGet<any>(
    (db as any).select().from(legalPages).where(eq((legalPages as any).slug, slug))
  );
  
  if (!page) {
    return c.json({ error: 'Legal page not found' }, 404);
  }
  
  return c.json({ 
    page: {
      ...page,
      hasEnglish: Boolean(page.contentText),
      hasSpanish: Boolean(page.contentTextEs),
    }
  });
});

// Update legal page (admin only)
// Note: No creation or deletion - only updates are allowed
// Accepts markdown content from rich text editor
legalPagesRouter.put('/admin/:slug', requireAuth(['admin']), async (c) => {
  const { slug } = c.req.param();
  const user = (c as any).get('user');
  const body = await c.req.json();
  // Accept both contentText (legacy plain text) and contentMarkdown (from rich text editor)
  const { contentText, contentTextEs, contentMarkdown, contentMarkdownEs, title, titleEs } = body;
  
  // Determine content - prefer markdown if provided, fall back to contentText
  const enContent = contentMarkdown !== undefined ? contentMarkdown : contentText;
  const esContent = contentMarkdownEs !== undefined ? contentMarkdownEs : contentTextEs;
  
  // At least one content field is required
  if (!enContent && !esContent) {
    return c.json({ error: 'At least one language content is required' }, 400);
  }

  // Bound the sizes of admin-supplied content to avoid unbounded payloads.
  const MAX_CONTENT_LEN = 200000; // ~200 KB of markdown per language
  const MAX_TITLE_LEN = 255;
  const tooLong = (v: any, max: number) => typeof v === 'string' && v.length > max;
  if (tooLong(enContent, MAX_CONTENT_LEN) || tooLong(esContent, MAX_CONTENT_LEN)) {
    return c.json({ error: `Content must be at most ${MAX_CONTENT_LEN} characters` }, 400);
  }
  if (tooLong(title, MAX_TITLE_LEN) || tooLong(titleEs, MAX_TITLE_LEN)) {
    return c.json({ error: `Title must be at most ${MAX_TITLE_LEN} characters` }, 400);
  }
  
  const existing = await dbGet(
    (db as any)
      .select()
      .from(legalPages)
      .where(eq((legalPages as any).slug, slug))
  );
  
  if (!existing) {
    return c.json({ error: 'Legal page not found' }, 404);
  }
  
  const updateData: any = {
    updatedAt: getNow(),
    updatedBy: user?.id || null,
  };
  
  // Update English content if provided
  if (enContent !== undefined) {
    // Store markdown directly (from rich text editor)
    updateData.contentMarkdown = enContent;
    // Derive plain text from markdown
    updateData.contentText = markdownToText(enContent);
  }
  
  // Update Spanish content if provided
  if (esContent !== undefined) {
    updateData.contentMarkdownEs = esContent || null;
    updateData.contentTextEs = esContent ? markdownToText(esContent) : null;
  }
  
  // Allow updating titles
  if (title !== undefined) {
    updateData.title = title;
  }
  if (titleEs !== undefined) {
    updateData.titleEs = titleEs || null;
  }
  
  await (db as any)
    .update(legalPages)
    .set(updateData)
    .where(eq((legalPages as any).slug, slug));
  
  const updated = await dbGet<any>(
    (db as any).select().from(legalPages).where(eq((legalPages as any).slug, slug))
  );
  
  return c.json({ 
    page: {
      ...updated,
      hasEnglish: Boolean(updated.contentText),
      hasSpanish: Boolean(updated.contentTextEs),
    },
    message: 'Legal page updated successfully' 
  });
});

// Seed legal pages from filesystem (admin only)
// This imports markdown files and converts them to plain text for editing
// Files are imported as English content - Spanish can be added manually
legalPagesRouter.post('/admin/seed', requireAuth(['admin']), async (c) => {
  const user = (c as any).get('user');
  
  // Check if table already has data
  const existingPages = await dbAll(
    (db as any)
      .select({ id: (legalPages as any).id })
      .from(legalPages)
      .limit(1)
  );
  
  if (existingPages.length > 0) {
    return c.json({ 
      message: 'Legal pages already seeded. Use update to modify pages.',
      seeded: 0 
    });
  }
  
  const legalDir = getLegalDir();
  
  if (!fs.existsSync(legalDir)) {
    return c.json({ error: `Legal directory not found: ${legalDir}` }, 400);
  }
  
  const files = fs.readdirSync(legalDir).filter(f => f.endsWith('.md'));
  const seededPages: string[] = [];
  const now = getNow();
  
  for (const file of files) {
    const filePath = path.join(legalDir, file);
    const contentMarkdown = fs.readFileSync(filePath, 'utf-8');
    const slug = fileNameToSlug(file);
    const contentText = markdownToText(contentMarkdown);
    const titles = titleMap[slug];
    const title = titles?.en || extractTitleFromMarkdown(contentMarkdown);
    const titleEs = titles?.es || null;
    
    await (db as any).insert(legalPages).values({
      id: generateId(),
      slug,
      title,
      titleEs,
      contentText, // English plain text
      contentTextEs: null, // Spanish to be added manually
      contentMarkdown, // English markdown
      contentMarkdownEs: null, // Spanish to be generated when contentTextEs is set
      updatedAt: now,
      updatedBy: user?.id || null,
      createdAt: now,
    });
    
    seededPages.push(slug);
  }
  
  return c.json({ 
    message: `Successfully seeded ${seededPages.length} legal pages (English content imported, Spanish can be added via editor)`,
    seeded: seededPages.length,
    pages: seededPages,
  });
});

export default legalPagesRouter;
