// Articles table query functions with Perfect SEO enforcement
// Includes automatic SEO metadata mapping for Astro <head> components

import { pool } from '@/lib/db';
import type { Article, FilterOptions, PaginationResult } from './types';
import { buildWhere, buildSearch, buildPagination, buildUpdateSet, getSingleResult, isValidUUID } from './utils';

/**
 * Get all articles with optional filtering and pagination
 */
export async function getArticles(options: FilterOptions = {}): Promise<PaginationResult<Article>> {
    const { limit = 50, offset = 0, status, search, siteId } = options;

    let sql = 'SELECT * FROM generated_articles WHERE 1=1';
    const params: any[] = [];
    let paramIndex = 1;

    // Add status filter
    if (status) {
        sql += ` AND status = $${paramIndex++}`;
        params.push(status);
    }

    // Add site filter
    if (siteId) {
        sql += ` AND site_id = $${paramIndex++}`;
        params.push(siteId);
    }

    // Add search filter (searches title)
    if (search) {
        const [searchSql, searchParam] = buildSearch('title', search, paramIndex++);
        sql += searchSql;
        params.push(searchParam);
    }

    // Add pagination
    const [paginationSql, safeLimit, safeOffset] = buildPagination(limit, offset, paramIndex);
    sql += ' ORDER BY created_at DESC' + paginationSql;
    params.push(safeLimit, safeOffset);

    // Execute query
    const { rows } = await pool.query<Article>(sql, params);

    // Get total count
    const countSql = 'SELECT COUNT(*) FROM generated_articles WHERE 1=1' +
        (status ? ` AND status = $1` : '') +
        (siteId ? ` AND site_id = $${status ? 2 : 1}` : '');
    const countParams = [status, siteId].filter(Boolean);
    const { rows: countRows } = await pool.query<{ count: string }>(countSql, countParams);
    const total = parseInt(countRows[0]?.count || '0');

    return {
        data: rows,
        total,
        limit: safeLimit,
        offset: safeOffset,
        hasMore: safeOffset + rows.length < total
    };
}

/**
 * Get single article by ID
 */
export async function getArticleById(id: string): Promise<Article | null> {
    if (!isValidUUID(id)) {
        throw new Error('Invalid article ID format');
    }

    const { rows } = await pool.query<Article>(
        'SELECT * FROM generated_articles WHERE id = $1',
        [id]
    );
    return getSingleResult(rows);
}

/**
 * Get articles by site
 */
export async function getArticlesBySite(siteId: string, options: FilterOptions = {}): Promise<Article[]> {
    if (!isValidUUID(siteId)) {
        throw new Error('Invalid site ID format');
    }

    const { limit = 50, offset = 0, status } = options;

    let sql = 'SELECT * FROM generated_articles WHERE site_id = $1';
    const params: any[] = [siteId];
    let paramIndex = 2;

    if (status) {
        sql += ` AND status = $${paramIndex++}`;
        params.push(status);
    }

    const [paginationSql, safeLimit, safeOffset] = buildPagination(limit, offset, paramIndex);
    sql += ' ORDER BY created_at DESC' + paginationSql;
    params.push(safeLimit, safeOffset);

    const { rows } = await pool.query<Article>(sql, params);
    return rows;
}

/**
 * Get articles by status
 */
export async function getArticlesByStatus(status: string): Promise<Article[]> {
    const { rows } = await pool.query<Article>(
        'SELECT * FROM generated_articles WHERE status = $1 ORDER BY created_at DESC LIMIT 100',
        [status]
    );
    return rows;
}

/**
 * Create new article with Zod validation and SEO enforcement
 * ENFORCES "Perfect SEO" - all metadata must be provided
 */
export async function createArticle(data: unknown): Promise<Article> {
    // Import schemas
    const { ArticleSchema, validateForCreate } = await import('./schemas');

    // 1. Validate input (enforces SEO metadata presence)
    const validatedData = validateForCreate(ArticleSchema, data, 'Article');

    // 2. Ensure SEO data is complete before allowing publish
    if (validatedData.status === 'published' && !validatedData.seo_data) {
        throw new Error('Cannot publish article without complete SEO metadata');
    }

    // 3. Execute SQL with clean, validated data
    const { rows } = await pool.query<Article>(
        `INSERT INTO generated_articles 
     (site_id, title, content, status, is_published)
     VALUES ($1, $2, $3, $4, $5)
     RETURNING *`,
        [
            validatedData.site_id,
            validatedData.title,
            validatedData.content,
            validatedData.status,
            validatedData.is_published
        ]
    );

    if (rows.length === 0) {
        throw new Error('Failed to create article');
    }

    return rows[0];
}

/**
 * Update existing article with Zod validation
 */
export async function updateArticle(id: string, data: unknown): Promise<Article> {
    if (!isValidUUID(id)) {
        throw new Error('Invalid article ID format');
    }

    // Import schemas
    const { PartialArticleSchema, validateForUpdate } = await import('./schemas');

    // 1. Validate partial update data
    const validatedData = validateForUpdate(
        PartialArticleSchema,
        { ...(data as Record<string, any>), id },
        'Article'
    );

    // 2. If publishing, ensure SEO is complete
    if (validatedData.status === 'published' || validatedData.is_published) {
        // Fetch existing article to check SEO
        const existing = await getArticleById(id);
        if (!existing) {
            throw new Error('Article not found');
        }

        // Check if SEO data exists (either in update or in existing article)
        const hasSEO = validatedData.seo_data || (existing as any).seo_data;
        if (!hasSEO) {
            throw new Error('Cannot publish article without SEO metadata. Please add seo_data.');
        }
    }

    // 3. Build UPDATE query from validated data
    const [setClause, values] = buildUpdateSet(validatedData);
    values.push(id);

    // 4. Execute SQL
    const { rows } = await pool.query<Article>(
        `UPDATE generated_articles SET ${setClause}, updated_at = NOW()
     WHERE id = $${values.length}
     RETURNING *`,
        values
    );

    if (rows.length === 0) {
        throw new Error('Article not found');
    }

    return rows[0];
}

/**
 * Delete article
 */
export async function deleteArticle(id: string): Promise<boolean> {
    if (!isValidUUID(id)) {
        throw new Error('Invalid article ID format');
    }

    const result = await pool.query('DELETE FROM generated_articles WHERE id = $1', [id]);
    return result.rowCount ? result.rowCount > 0 : false;
}

/**
 * Publish article (ensures SEO validation)
 */
export async function publishArticle(id: string): Promise<Article> {
    const article = await getArticleById(id);

    if (!article) {
        throw new Error('Article not found');
    }

    // Enforce SEO metadata before publishing
    if (!(article as any).seo_data) {
        throw new Error(
            'Cannot publish article without SEO metadata. ' +
            'Please update the article with seo_data containing: title, description, keywords, og_image'
        );
    }

    return updateArticle(id, {
        status: 'published',
        is_published: true,
        published_at: new Date()
    });
}

/**
 * Get articles count by status
 */
export async function getArticlesCountByStatus(): Promise<Record<string, number>> {
    const { rows } = await pool.query<{ status: string; count: string }>(
        'SELECT status, COUNT(*) as count FROM generated_articles GROUP BY status'
    );

    return rows.reduce((acc, row) => {
        acc[row.status] = parseInt(row.count);
        return acc;
    }, {} as Record<string, number>);
}

/**
 * UTILITY: Extract SEO metadata for Astro <head> component
 * 
 * Usage in Astro page:
 * ---
 * const article = await getArticleById(params.id);
 * const seo = extractSEOForHead(article);
 * ---
 * <head>
 *   <title>{seo.title}</title>
 *   <meta name="description" content={seo.description} />
 *   {seo.ogImage && <meta property="og:image" content={seo.ogImage} />}
 * </head>
 */
export function extractSEOForHead(article: Article | null) {
    if (!article) {
        return null;
    }

    const seoData = (article as any).seo_data;

    if (!seoData) {
        // Fallback to article data
        return {
            title: article.title,
            description: (article as any).excerpt || article.content.slice(0, 160),
            keywords: [],
            ogImage: null,
            canonical: null
        };
    }

    return {
        title: seoData.title || article.title,
        description: seoData.description,
        keywords: seoData.keywords || [],
        ogImage: seoData.og_image || null,
        canonical: seoData.canonical_url || null,
        ogType: seoData.og_type || 'article',
        schemaMarkup: seoData.schema_markup || null
    };
}
