import database from "../../config/db";
import { QueryResult } from "pg";

export interface UpdateCreateData {
  product_id: string;
  version: string;
  version_type: "major" | "minor" | "patch" | "beta" | "alpha";
  title: string;
  description?: string;
  new_features?: any[];
  improvements?: any[];
  bug_fixes?: any[];
  breaking_changes?: any[];
  highlights?: string[];
  release_notes?: string;
  release_date: Date;
  is_latest?: boolean;
  is_beta?: boolean;
  is_public?: boolean;
  status?: string;
  slug?: string;
  meta_title?: string;
  meta_description?: string;
  created_by: string;
}

export interface UpdateUpdateData extends Partial<UpdateCreateData> {
  upvotes?: number;
  views?: number;
  published_at?: Date;
}

export interface UpdateFilters {
  page?: number;
  limit?: number;
  product_id?: string;
  created_by?: string;
  version_type?: string;
  status?: string;
  is_public?: boolean;
  is_latest?: boolean;
  is_beta?: boolean;
  search?: string;
  from_date?: Date;
  to_date?: Date;
  sort_by?: string;
  order?: "asc" | "desc";
}

export const productUpdateService = {
  // Create new product update
  async createUpdate(data: UpdateCreateData) {
    const {
      product_id,
      version,
      version_type = "patch",
      title,
      description,
      new_features = [],
      improvements = [],
      bug_fixes = [],
      breaking_changes = [],
      highlights = [],
      release_notes,
      release_date,
      is_latest = false,
      is_beta = false,
      is_public = true,
      status = "draft",
      slug,
      meta_title,
      meta_description,
      created_by,
    } = data;

    // Validation
    if (!product_id) {
      throw new Error("Product ID is required");
    }

    if (!version) {
      throw new Error("Version is required");
    }

    if (!title || title.trim().length < 3) {
      throw new Error("Title must be at least 3 characters");
    }

    if (!release_date) {
      throw new Error("Release date is required");
    }

    if (!created_by) {
      throw new Error("Created by user ID is required");
    }

    // Validate version format
    const versionRegex = /^v?[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\.]+)?$/;
    if (!versionRegex.test(version)) {
      throw new Error("Invalid version format. Use semantic versioning: x.y.z");
    }

    // Check if product exists
    const productCheck = await database.query(
      `SELECT id, creator_id FROM products WHERE id = $1 AND status = 'active'`,
      [product_id],
    );

    if (productCheck.rows.length === 0) {
      throw new Error("Product not found or not active");
    }

    // Check if user has permission to create updates
    const userCheck = await database.query(
      `SELECT id FROM accounts WHERE id = $1 AND is_active = true`,
      [created_by],
    );

    if (userCheck.rows.length === 0) {
      throw new Error("User not found");
    }

    // Check if version already exists for this product
    const versionCheck = await database.query(
      `SELECT id FROM products_updates WHERE product_id = $1 AND version = $2`,
      [product_id, version],
    );

    if (versionCheck.rows.length > 0) {
      throw new Error("Version already exists for this product");
    }

    // Generate slug if not provided
    const updateSlug = slug || this.generateSlug(version, title);

    // Check if slug already exists
    const slugCheck = await database.query(
      `SELECT id FROM products_updates WHERE slug = $1`,
      [updateSlug],
    );

    if (slugCheck.rows.length > 0) {
      throw new Error("Slug already exists");
    }

    // If setting as latest, handle existing latest
    if (is_latest) {
      await this.handleLatestUpdate(product_id);
    }

    // Set published_at if status is published
    let publishedAt = null;
    if (status === "published") {
      publishedAt = new Date();
    }

    const query = `
      INSERT INTO products_updates (
        product_id, version, version_type, title, description,
        new_features, improvements, bug_fixes, breaking_changes,
        highlights, release_notes, release_date, is_latest, is_beta,
        is_public, status, slug, meta_title, meta_description,
        created_by, published_at
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)
      RETURNING *;
    `;

    const values = [
      product_id,
      version,
      version_type,
      title.trim(),
      description?.trim(),
      new_features,
      improvements,
      bug_fixes,
      breaking_changes,
      highlights,
      release_notes?.trim(),
      release_date,
      is_latest,
      is_beta,
      is_public,
      status,
      updateSlug,
      meta_title,
      meta_description,
      created_by,
      publishedAt,
    ];

    const result = await database.query(query, values);
    return result.rows[0];
  },

  // Get update by ID
  async getUpdateById(id: string, incrementViews: boolean = true) {
    const query = `
      SELECT 
        u.*,
        product.name as product_name,
        product.slug as product_slug,
        product.logo as product_logo,
        creator.username as created_by_username,
        creator.display_name as created_by_display_name,
        creator.avatar as created_by_avatar,
        (
        SELECT JSON_AGG(
          JSON_BUILD_OBJECT(
            'id', p.id,
            'version', p.version,
            'title', p.title,
            'release_date', p.release_date
          )
        )
        FROM (
          SELECT id, version, title, release_date
          FROM products_updates
          WHERE product_id = u.product_id
            AND release_date < u.release_date
            AND status = 'published'
          ORDER BY release_date DESC
          LIMIT 3
        ) p
        ) AS previous_updates,
                (
          SELECT JSON_AGG(
            JSON_BUILD_OBJECT(
              'id', n.id,
              'version', n.version,
              'title', n.title,
              'release_date', n.release_date
            )
          )
          FROM (
            SELECT id, version, title, release_date
            FROM products_updates
            WHERE product_id = u.product_id
              AND release_date > u.release_date
              AND status = 'published'
            ORDER BY release_date ASC
            LIMIT 3
          ) n
        ) AS next_updates
      FROM products_updates u
      LEFT JOIN products product ON u.product_id = product.id
      LEFT JOIN accounts creator ON u.created_by = creator.id
      WHERE u.id = $1;
    `;

    const result = await database.query(query, [id]);
    const update = result.rows[0];

    if (update && incrementViews) {
      await this.incrementViews(id);
      update.views += 1;
    }

    return update || null;
  },

  // Get update by slug
  async getUpdateBySlug(slug: string, incrementViews: boolean = true) {
    const query = `
      SELECT 
        u.*,
        product.name as product_name,
        product.slug as product_slug,
        product.logo as product_logo,
        creator.username as created_by_username,
        creator.display_name as created_by_display_name,
        creator.avatar as created_by_avatar
      FROM products_updates u
      LEFT JOIN products product ON u.product_id = product.id
      LEFT JOIN accounts creator ON u.created_by = creator.id
      WHERE u.slug = $1;
    `;

    const result = await database.query(query, [slug]);
    const update = result.rows[0];

    if (update && incrementViews) {
      await this.incrementViews(update.id);
      update.views += 1;
    }

    return update || null;
  },

  // Get all updates with filters
  async getAllUpdates(filters: UpdateFilters = {}) {
    const {
      page = 1,
      limit = 20,
      product_id,
      created_by,
      version_type,
      status = "published",
      is_public = true,
      is_latest,
      is_beta,
      search,
      from_date,
      to_date,
      sort_by = "release_date",
      order = "desc",
    } = filters;

    const offset = (page - 1) * limit;
    const whereClauses: string[] = [];
    const values: any[] = [];
    let paramCount = 0;

    // Status filter
    paramCount++;
    whereClauses.push(`u.status = $${paramCount}`);
    values.push(status);

    // Public filter
    if (is_public !== undefined) {
      paramCount++;
      whereClauses.push(`u.is_public = $${paramCount}`);
      values.push(is_public);
    }

    // Product filter
    if (product_id) {
      paramCount++;
      whereClauses.push(`u.product_id = $${paramCount}`);
      values.push(product_id);
    }

    // Created by filter
    if (created_by) {
      paramCount++;
      whereClauses.push(`u.created_by = $${paramCount}`);
      values.push(created_by);
    }

    // Version type filter
    if (version_type) {
      paramCount++;
      whereClauses.push(`u.version_type = $${paramCount}`);
      values.push(version_type);
    }

    // Latest filter
    if (is_latest !== undefined) {
      paramCount++;
      whereClauses.push(`u.is_latest = $${paramCount}`);
      values.push(is_latest);
    }

    // Beta filter
    if (is_beta !== undefined) {
      paramCount++;
      whereClauses.push(`u.is_beta = $${paramCount}`);
      values.push(is_beta);
    }

    // Date range filter
    if (from_date) {
      paramCount++;
      whereClauses.push(`u.release_date >= $${paramCount}`);
      values.push(from_date);
    }

    if (to_date) {
      paramCount++;
      whereClauses.push(`u.release_date <= $${paramCount}`);
      values.push(to_date);
    }

    // Search filter
    if (search) {
      paramCount++;
      whereClauses.push(`
        (u.title ILIKE $${paramCount} OR 
         u.description ILIKE $${paramCount} OR 
         u.release_notes ILIKE $${paramCount} OR
         u.version ILIKE $${paramCount})
      `);
      values.push(`%${search}%`);
    }

    const whereClause =
      whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";

    // Validate sort field
    const validSortFields = [
      "release_date",
      "created_at",
      "updated_at",
      "version",
      "upvotes",
      "views",
      "title",
    ];
    const sortField = validSortFields.includes(sort_by)
      ? sort_by
      : "release_date";
    const sortOrder = order === "asc" ? "ASC" : "DESC";

    // Count total updates
    const countQuery = `
      SELECT COUNT(*) as total
      FROM products_updates u
      ${whereClause};
    `;

    const countResult = await database.query(countQuery, values);
    const total = parseInt(countResult.rows[0].total);

    // Get paginated updates
    paramCount = values.length;
    const dataQuery = `
      SELECT 
        u.*,
        product.name as product_name,
        product.slug as product_slug,
        product.logo as product_logo,
        creator.username as created_by_username,
        creator.display_name as created_by_display_name
      FROM products_updates u
      LEFT JOIN products product ON u.product_id = product.id
      LEFT JOIN accounts creator ON u.created_by = creator.id
      ${whereClause}
      ORDER BY u.${sortField} ${sortOrder}
      LIMIT $${paramCount + 1} OFFSET $${paramCount + 2};
    `;

    const dataValues = [...values, limit, offset];
    const dataResult = await database.query(dataQuery, dataValues);

    return {
      data: dataResult.rows,
      pagination: {
        page,
        limit,
        total,
        total_pages: Math.ceil(total / limit),
        has_next: page * limit < total,
        has_prev: page > 1,
      },
    };
  },

  // Get product's updates
  async getProductUpdates(productId: string, filters: UpdateFilters = {}) {
    return this.getAllUpdates({
      ...filters,
      product_id: productId,
    });
  },

  // Get latest update for a product
  async getLatestUpdate(productId: string) {
    const query = `
      SELECT 
        u.*,
        product.name as product_name,
        product.slug as product_slug,
        creator.username as created_by_username,
        creator.display_name as created_by_display_name
      FROM products_updates u
      LEFT JOIN products product ON u.product_id = product.id
      LEFT JOIN accounts creator ON u.created_by = creator.id
      WHERE u.product_id = $1 
        AND u.status = 'published' 
        AND u.is_latest = true
      LIMIT 1;
    `;

    const result = await database.query(query, [productId]);
    return result.rows[0] || null;
  },

  // Update product update
  async updateUpdate(id: string, data: UpdateUpdateData, userId?: string) {
    // Check if update exists
    const existingUpdate = await this.getUpdateById(id, false);
    if (!existingUpdate) {
      throw new Error("Update not found");
    }

    // Check permissions if userId is provided
    if (userId) {
      const hasPermission = await this.checkUpdatePermission(id, userId);
      if (!hasPermission) {
        throw new Error("You don't have permission to update this update");
      }
    }

    const setClauses: string[] = [];
    const values: any[] = [];
    let paramCount = 0;

    const fields = [
      "version",
      "version_type",
      "title",
      "description",
      "new_features",
      "improvements",
      "bug_fixes",
      "breaking_changes",
      "highlights",
      "release_notes",
      "release_date",
      "is_latest",
      "is_beta",
      "is_public",
      "status",
      "slug",
      "meta_title",
      "meta_description",
      "upvotes",
      "views",
    ];

    fields.forEach((field) => {
      if (data[field as keyof UpdateUpdateData] !== undefined) {
        paramCount++;
        setClauses.push(`${field} = $${paramCount}`);
        values.push(data[field as keyof UpdateUpdateData]);
      }
    });

    // Handle latest update logic
    if (data.is_latest === true) {
      await this.handleLatestUpdate(existingUpdate.product_id, id);
    }

    // Handle status change to published
    if (data.status === "published" && existingUpdate.status !== "published") {
      paramCount++;
      setClauses.push(`published_at = CURRENT_TIMESTAMP`);
    }

    if (setClauses.length === 0) {
      throw new Error("No fields to update");
    }

    paramCount++;
    setClauses.push(`updated_at = CURRENT_TIMESTAMP`);
    values.push(id);

    const query = `
      UPDATE products_updates
      SET ${setClauses.join(", ")}
      WHERE id = $${paramCount}
      RETURNING *;
    `;

    const result = await database.query(query, values);
    return result.rows[0];
  },

  // Delete update
  async deleteUpdate(id: string, userId?: string) {
    // Check if update exists
    const existingUpdate = await this.getUpdateById(id, false);
    if (!existingUpdate) {
      throw new Error("Update not found");
    }

    // Check permissions if userId is provided
    if (userId) {
      const hasPermission = await this.checkUpdatePermission(id, userId);
      if (!hasPermission) {
        throw new Error("You don't have permission to delete this update");
      }
    }

    // If this is the latest update, set another as latest
    if (existingUpdate.is_latest) {
      await this.setNewLatestUpdate(existingUpdate.product_id, id);
    }

    const query = `
      DELETE FROM products_updates
      WHERE id = $1
      RETURNING *;
    `;

    const result = await database.query(query, [id]);
    return result.rows[0];
  },

  // Upvote an update
  async upvoteUpdate(updateId: string, userId: string) {
    // Check if update exists and is published
    const update = await database.query(
      `SELECT id FROM products_updates WHERE id = $1 AND status = 'published'`,
      [updateId],
    );

    if (update.rows.length === 0) {
      throw new Error("Update not found or not published");
    }

    // Here you would typically check if user has already voted
    // For now, just increment
    const query = `
      UPDATE products_updates
      SET upvotes = upvotes + 1, updated_at = CURRENT_TIMESTAMP
      WHERE id = $1
      RETURNING upvotes;
    `;

    const result = await database.query(query, [updateId]);
    return result.rows[0];
  },

  // Get update statistics for a product
  async getUpdateStats(productId: string) {
    const query = `
      SELECT 
        COUNT(*) as total_updates,
        COUNT(CASE WHEN status = 'published' THEN 1 END) as published_updates,
        COUNT(CASE WHEN status = 'draft' THEN 1 END) as draft_updates,
        COUNT(CASE WHEN status = 'scheduled' THEN 1 END) as scheduled_updates,
        COUNT(CASE WHEN version_type = 'major' THEN 1 END) as major_updates,
        COUNT(CASE WHEN version_type = 'minor' THEN 1 END) as minor_updates,
        COUNT(CASE WHEN version_type = 'patch' THEN 1 END) as patch_updates,
        COUNT(CASE WHEN version_type = 'beta' THEN 1 END) as beta_updates,
        COUNT(CASE WHEN version_type = 'alpha' THEN 1 END) as alpha_updates,
        COUNT(CASE WHEN is_beta = true THEN 1 END) as beta_releases,
        MIN(release_date) as first_release,
        MAX(release_date) as last_release,
        SUM(upvotes) as total_upvotes,
        SUM(views) as total_views
      FROM products_updates
      WHERE product_id = $1;
    `;

    const result = await database.query(query, [productId]);
    return result.rows[0];
  },

  // Get version history for a product
  async getVersionHistory(productId: string) {
    const query = `
      SELECT 
        version,
        version_type,
        title,
        release_date,
        is_latest,
        is_beta,
        upvotes,
        views,
        slug
      FROM products_updates
      WHERE product_id = $1 AND status = 'published'
      ORDER BY 
        CASE version_type
          WHEN 'major' THEN 1
          WHEN 'minor' THEN 2
          WHEN 'patch' THEN 3
          WHEN 'beta' THEN 4
          WHEN 'alpha' THEN 5
        END,
        release_date DESC;
    `;

    const result = await database.query(query, [productId]);
    return result.rows;
  },

  // Get recent updates across all products
  async getRecentUpdates(limit: number = 10) {
    const query = `
      SELECT 
        u.*,
        product.name as product_name,
        product.slug as product_slug,
        product.logo as product_logo,
        creator.username as created_by_username,
        creator.display_name as created_by_display_name
      FROM products_updates u
      LEFT JOIN products product ON u.product_id = product.id
      LEFT JOIN accounts creator ON u.created_by = creator.id
      WHERE u.status = 'published' AND u.is_public = true
      ORDER BY u.release_date DESC
      LIMIT $1;
    `;

    const result = await database.query(query, [limit]);
    return result.rows;
  },

  // Get updates by version type
  async getUpdatesByType(productId: string, versionType: string) {
    const validTypes = ["major", "minor", "patch", "beta", "alpha"];
    if (!validTypes.includes(versionType)) {
      throw new Error(
        `Invalid version type. Must be one of: ${validTypes.join(", ")}`,
      );
    }

    const query = `
      SELECT 
        u.*,
        product.name as product_name,
        product.slug as product_slug
      FROM products_updates u
      LEFT JOIN products product ON u.product_id = product.id
      WHERE u.product_id = $1 
        AND u.version_type = $2 
        AND u.status = 'published'
      ORDER BY u.release_date DESC;
    `;

    const result = await database.query(query, [productId, versionType]);
    return result.rows;
  },

  // Get changelog for a product
  async getChangelog(productId: string, limit: number = 20) {
    const query = `
      SELECT 
        version,
        version_type,
        title,
        release_date,
        new_features,
        improvements,
        bug_fixes,
        breaking_changes,
        highlights,
        upvotes,
        slug
      FROM products_updates
      WHERE product_id = $1 AND status = 'published'
      ORDER BY release_date DESC
      LIMIT $2;
    `;

    const result = await database.query(query, [productId, limit]);
    return result.rows;
  },

  // Check for new updates since last viewed
  async getNewUpdatesSince(productId: string, lastViewed: Date) {
    const query = `
      SELECT 
        COUNT(*) as new_updates_count,
        JSON_AGG(
          JSON_BUILD_OBJECT(
            'id', id,
            'version', version,
            'title', title,
            'release_date', release_date,
            'version_type', version_type
          )
        ) as updates
      FROM products_updates
      WHERE product_id = $1 
        AND status = 'published' 
        AND release_date > $2
      ORDER BY release_date DESC;
    `;

    const result = await database.query(query, [productId, lastViewed]);
    return result.rows[0];
  },

  // Bulk publish updates
  async bulkPublishUpdates(updateIds: string[], userId: string) {
    if (!Array.isArray(updateIds) || updateIds.length === 0) {
      throw new Error("Update IDs array is required");
    }

    // Check permissions for all updates
    for (const updateId of updateIds) {
      const hasPermission = await this.checkUpdatePermission(updateId, userId);
      if (!hasPermission) {
        throw new Error(
          `You don't have permission to publish update ${updateId}`,
        );
      }
    }

    const query = `
      UPDATE products_updates
      SET status = 'published', 
          published_at = CURRENT_TIMESTAMP,
          updated_at = CURRENT_TIMESTAMP
      WHERE id = ANY($1)
      RETURNING *;
    `;

    const result = await database.query(query, [updateIds]);
    return result.rows;
  },

  // Generate slug from version and title
  generateSlug(version: string, title: string): string {
    const cleanVersion = version.replace(/^v/, ""); // Remove leading 'v'
    const cleanTitle = title
      .toLowerCase()
      .replace(/[^a-z0-9\s-]/g, "")
      .replace(/\s+/g, "-")
      .replace(/--+/g, "-")
      .trim();

    return `${cleanVersion}-${cleanTitle}`;
  },

  // Increment views
  async incrementViews(updateId: string) {
    const query = `
      UPDATE products_updates
      SET views = views + 1
      WHERE id = $1;
    `;

    await database.query(query, [updateId]);
  },

  // Handle latest update logic
  async handleLatestUpdate(productId: string, excludeId?: string) {
    // Clear existing latest
    let query = `
      UPDATE products_updates
      SET is_latest = false, updated_at = CURRENT_TIMESTAMP
      WHERE product_id = $1 AND is_latest = true
    `;

    const values: any[] = [productId];

    if (excludeId) {
      query += ` AND id != $2`;
      values.push(excludeId);
    }

    await database.query(query, values);
  },

  // Set new latest update when current is deleted
  async setNewLatestUpdate(productId: string, excludeId: string) {
    // Find the most recent published update
    const query = `
      UPDATE products_updates
      SET is_latest = true, updated_at = CURRENT_TIMESTAMP
      WHERE id = (
        SELECT id
        FROM products_updates
        WHERE product_id = $1 
          AND id != $2 
          AND status = 'published'
        ORDER BY release_date DESC
        LIMIT 1
      )
      RETURNING *;
    `;

    const result = await database.query(query, [productId, excludeId]);
    return result.rows[0];
  },

  // Check if user has permission to modify update
  async checkUpdatePermission(
    updateId: string,
    userId: string,
  ): Promise<boolean> {
    // Check if user is update creator
    const updateQuery = await database.query(
      `SELECT created_by, product_id FROM products_updates WHERE id = $1`,
      [updateId],
    );

    if (updateQuery.rows.length === 0) {
      return false;
    }

    const update = updateQuery.rows[0];

    if (update.created_by === userId) {
      return true;
    }

    // Check if user is product owner
    const productQuery = await database.query(
      `SELECT creator_id FROM products WHERE id = $1`,
      [update.product_id],
    );

    if (
      productQuery.rows.length > 0 &&
      productQuery.rows[0].creator_id === userId
    ) {
      return true;
    }

    // Check if user is admin
    const adminCheck = await database.query(
      `SELECT EXISTS(
        SELECT 1 FROM role_assignments ra
        INNER JOIN roles r ON ra.role_id = r.id
        WHERE ra.account_id = $1 
          AND ra.is_active = true
          AND (r.name = 'admin' OR r.name = 'super_admin')
      ) as is_admin`,
      [userId],
    );

    return adminCheck.rows[0]?.is_admin || false;
  },

  // Get update timeline for product
  async getUpdateTimeline(productId: string) {
    const query = `
      SELECT 
        EXTRACT(YEAR FROM release_date) as year,
        EXTRACT(MONTH FROM release_date) as month,
        COUNT(*) as update_count,
        JSON_AGG(
          JSON_BUILD_OBJECT(
            'id', id,
            'version', version,
            'title', title,
            'version_type', version_type,
            'release_date', release_date,
            'is_latest', is_latest
          )
          ORDER BY release_date DESC
        ) as updates
      FROM products_updates
      WHERE product_id = $1 AND status = 'published'
      GROUP BY EXTRACT(YEAR FROM release_date), EXTRACT(MONTH FROM release_date)
      ORDER BY year DESC, month DESC;
    `;

    const result = await database.query(query, [productId]);
    return result.rows;
  },

  // Search updates across all products
  async searchUpdates(queryText: string, filters: any = {}) {
    const { limit = 20, product_id, version_type } = filters;

    const whereClauses: string[] = [
      `u.status = 'published'`,
      `u.is_public = true`,
      `(
        u.title ILIKE $1 OR 
        u.description ILIKE $1 OR 
        u.release_notes ILIKE $1 OR
        u.version ILIKE $1
      )`,
    ];

    const values: any[] = [`%${queryText}%`];
    let paramCount = 1;

    if (product_id) {
      paramCount++;
      whereClauses.push(`u.product_id = $${paramCount}`);
      values.push(product_id);
    }

    if (version_type) {
      paramCount++;
      whereClauses.push(`u.version_type = $${paramCount}`);
      values.push(version_type);
    }

    const whereClause = `WHERE ${whereClauses.join(" AND ")}`;

    const query = `
      SELECT 
        u.*,
        product.name as product_name,
        product.slug as product_slug,
        product.logo as product_logo,
        ts_rank(
          setweight(to_tsvector('english', u.title), 'A') || 
          setweight(to_tsvector('english', COALESCE(u.description, '')), 'B') || 
          setweight(to_tsvector('english', COALESCE(u.release_notes, '')), 'C'),
          plainto_tsquery('english', $1)
        ) as rank
      FROM products_updates u
      LEFT JOIN products product ON u.product_id = product.id
      ${whereClause}
      ORDER BY rank DESC, u.release_date DESC
      LIMIT $${paramCount + 1};
    `;

    values.push(limit);
    const result = await database.query(query, values);
    return result.rows;
  },
};
