import { v4 as uuidv4 } from "uuid";
import { getAdapter } from "../driver.js";

function rowToLimits(row) {
  if (!row) return null;
  return {
    id: row.id,
    userId: row.userId,
    packageId: row.packageId,
    rtpMinute: row.rtpMinute,
    rtpDay: row.rtpDay,
    tokenLimitMonthly: row.tokenLimitMonthly,
    creditLimit: row.creditLimit,
    maxConcurrent: row.maxConcurrent,
    created_at: row.created_at,
    updated_at: row.updated_at,
  };
}

export async function createDefaults(userId, packageId = null) {
  const db = await getAdapter();
  const id = uuidv4();
  const now = new Date().toISOString();
  db.run(
    `INSERT INTO rateLimits(id, userId, packageId, rtpMinute, rtpDay, tokenLimitMonthly, creditLimit, maxConcurrent, created_at, updated_at) VALUES(?, ?, ?, 100, 100000, 1000000, 5.0, 5, ?, ?)`,
    [id, userId, packageId, now, now]
  );
  return { id, userId, packageId, rtpMinute: 100, rtpDay: 100000, tokenLimitMonthly: 1000000, creditLimit: 5.0, maxConcurrent: 5 };
}

export async function getByUserId(userId) {
  const db = await getAdapter();
  const row = db.get(`SELECT * FROM rateLimits WHERE userId = ?`, [userId]);
  return rowToLimits(row);
}

export async function updateLimits(userId, limits) {
  const db = await getAdapter();
  const now = new Date().toISOString();
  const fields = [];
  const values = [];
  for (const [key, value] of Object.entries(limits)) {
    if (!['packageId', 'rtpMinute', 'rtpDay', 'tokenLimitMonthly', 'creditLimit', 'maxConcurrent'].includes(key)) continue;
    fields.push(`${key} = ?`);
    values.push(value);
  }
  if (fields.length === 0) return;
  fields.push('updated_at = ?');
  values.push(now);
  values.push(userId);
  db.run(`UPDATE rateLimits SET ${fields.join(', ')} WHERE userId = ?`, values);
}

export async function getMonthlyTokens(userId) {
  const db = await getAdapter();
  const now = new Date();
  const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1).toISOString();
  const row = db.get(
    `SELECT COALESCE(SUM(uh.promptTokens), 0) + COALESCE(SUM(uh.completionTokens), 0) as totalTokens
     FROM usageHistory uh
     INNER JOIN apiKeys ak ON uh.apiKey = ak.key
     WHERE ak.userId = ? AND uh.timestamp >= ?`,
    [userId, startOfMonth]
  );
  return row ? (row.totalTokens || 0) : 0;
}

export async function getMonthlyCost(userId) {
  const db = await getAdapter();
  const now = new Date();
  const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1).toISOString();
  const row = db.get(
    `SELECT COALESCE(SUM(uh.cost), 0) as totalCost
     FROM usageHistory uh
     INNER JOIN apiKeys ak ON uh.apiKey = ak.key
     WHERE ak.userId = ? AND uh.timestamp >= ?`,
    [userId, startOfMonth]
  );
  return row ? (row.totalCost || 0) : 0;
}

export async function getEffectiveLimits(userId) {
  const db = await getAdapter();
  const row = db.get(
    `SELECT 
       p.rtpMinute as pkg_rtpMinute, 
       p.rtpDay as pkg_rtpDay, 
       p.tokenLimitMonthly as pkg_tokenLimitMonthly, 
       p.creditLimit as pkg_creditLimit, 
       p.maxConcurrent as pkg_maxConcurrent, 
       p.creditToTokenRatio as pkg_creditToTokenRatio,
       up.rtpMinuteOverride, 
       up.rtpDayOverride, 
       up.tokenLimitMonthlyOverride, 
       up.creditLimitOverride, 
       up.maxConcurrentOverride
     FROM userPackages up
     JOIN packages p ON up.packageId = p.id
     WHERE up.userId = ?`,
    [userId]
  );

  if (row) {
    return {
      rtpMinute: row.rtpMinuteOverride ?? row.pkg_rtpMinute,
      rtpDay: row.rtpDayOverride ?? row.pkg_rtpDay,
      tokenLimitMonthly: row.tokenLimitMonthlyOverride ?? row.pkg_tokenLimitMonthly,
      creditLimit: row.creditLimitOverride ?? row.pkg_creditLimit,
      maxConcurrent: row.maxConcurrentOverride ?? row.pkg_maxConcurrent,
      creditToTokenRatio: row.pkg_creditToTokenRatio
    };
  }

  const rateLimitRow = db.get(`SELECT * FROM rateLimits WHERE userId = ?`, [userId]);
  if (rateLimitRow) {
    return {
      rtpMinute: rateLimitRow.rtpMinute,
      rtpDay: rateLimitRow.rtpDay,
      tokenLimitMonthly: rateLimitRow.tokenLimitMonthly,
      creditLimit: rateLimitRow.creditLimit,
      maxConcurrent: rateLimitRow.maxConcurrent,
      creditToTokenRatio: 1000
    };
  }

  return {
    rtpMinute: 100,
    rtpDay: 100000,
    tokenLimitMonthly: 1000000,
    creditLimit: 5.0,
    maxConcurrent: 5,
    creditToTokenRatio: 1000
  };
}
