import { Pool } from 'pg';
import type { UserLicense, License, LicenseTier } from '../types/user.js';
import { UserLicenseSchema, LICENSE_TIER_TEMPLATES } from '../types/user.js';
import type { AuthService } from '../auth/auth-service.js';

export class UserService {
  private pool: Pool;
  private authService?: AuthService;

  constructor(connectionString: string) {
    this.pool = new Pool({
      connectionString,
      max: 20,
      idleTimeoutMillis: 30000,
      connectionTimeoutMillis: 2000,
    });
  }

  /**
   * Get the database pool (for AuthService)
   */
  getPool(): Pool {
    return this.pool;
  }

  /**
   * Set auth service for JWT verification
   * Called after AuthService is initialized
   */
  setAuthService(authService: AuthService): void {
    this.authService = authService;
  }

  /**
   * Get user license by user ID
   */
  async getUserLicense(userId: string): Promise<UserLicense | null> {
    const client = await this.pool.connect();
    try {
      const result = await client.query(
        `SELECT
          user_id as "userId",
          email,
          license,
          mcp_server_url as "mcpServerUrl",
          expires_at as "expiresAt",
          created_at as "createdAt",
          updated_at as "updatedAt"
        FROM user_licenses
        WHERE user_id = $1
          AND (expires_at IS NULL OR expires_at > NOW())`,
        [userId]
      );

      if (result.rows.length === 0) {
        return null;
      }

      const row = result.rows[0];

      // Parse and validate
      return UserLicenseSchema.parse({
        userId: row.userId,
        email: row.email,
        license: row.license,
        mcpServerUrl: row.mcpServerUrl,
        expiresAt: row.expiresAt,
        createdAt: row.createdAt,
        updatedAt: row.updatedAt,
      });
    } finally {
      client.release();
    }
  }

  /**
   * Get user ID from channel-specific identifier
   */
  async getUserIdFromChannel(channelType: string, channelUserId: string): Promise<string | null> {
    const client = await this.pool.connect();
    try {
      const result = await client.query(
        `SELECT user_id
        FROM user_channel_links
        WHERE channel_type = $1 AND channel_user_id = $2`,
        [channelType, channelUserId]
      );

      return result.rows.length > 0 ? result.rows[0].user_id : null;
    } finally {
      client.release();
    }
  }

  /**
   * Verify JWT token from web client
   * Uses Better Auth for proper JWT verification
   */
  async verifyWebToken(token: string): Promise<string | null> {
    if (!this.authService) {
      // Fallback for development - decode without verification
      // This allows backward compatibility during migration
      try {
        const payload = JSON.parse(
          Buffer.from(token.split('.')[1], 'base64').toString()
        );
        return payload.sub || null;
      } catch {
        return null;
      }
    }

    // Use Better Auth for proper verification
    return await this.authService.verifyToken(token);
  }

  /**
   * Re-apply the current canonical template for every user's declared licenseType.
   * Updates only the DB — does not touch deployments, so running pods are unaffected
   * until their next natural restart.
   */
  async migrateAllLicenses(): Promise<{ updated: number }> {
    const client = await this.pool.connect();
    try {
      const rows = await client.query(
        `SELECT user_id, license->>'licenseType' AS tier FROM user_licenses`
      );
      let updated = 0;
      for (const row of rows.rows) {
        const tier = row.tier as LicenseTier;
        if (!LICENSE_TIER_TEMPLATES[tier]) continue;
        await client.query(
          `UPDATE user_licenses SET license = $1::jsonb, updated_at = NOW() WHERE user_id = $2`,
          [JSON.stringify(LICENSE_TIER_TEMPLATES[tier]), row.user_id]
        );
        updated++;
      }
      return { updated };
    } finally {
      client.release();
    }
  }

  /**
   * Set a user's license to a canonical tier template.
   * Overwrites the existing license with the current template for that tier.
   */
  async setUserLicenseTier(userId: string, tier: LicenseTier): Promise<License> {
    const license = LICENSE_TIER_TEMPLATES[tier];
    const client = await this.pool.connect();
    try {
      await client.query(
        `INSERT INTO user_licenses (user_id, license, mcp_server_url, updated_at)
         VALUES ($1, $2::jsonb, 'pending', NOW())
         ON CONFLICT (user_id) DO UPDATE
           SET license = EXCLUDED.license, updated_at = NOW()`,
        [userId, JSON.stringify(license)]
      );
    } finally {
      client.release();
    }
    return license;
  }

  /**
   * Close database pool
   */
  async close(): Promise<void> {
    await this.pool.end();
  }
}
