/**
 * @ai-summary Terms agreement data access layer
 * @ai-context Provides parameterized SQL queries for terms agreement operations
 */

import { Pool, PoolClient } from 'pg';
import { TermsAgreement, CreateTermsAgreementRequest } from '../domain/terms-agreement.types';
import { logger } from '../../../core/logging/logger';

const TERMS_AGREEMENT_COLUMNS = `
  id, user_id, agreed_at, ip_address, user_agent,
  terms_version, terms_url, terms_content_hash,
  created_at, updated_at
`;

export class TermsAgreementRepository {
  constructor(private pool: Pool) {}

  /**
   * Create a new terms agreement record
   * Can accept a PoolClient for transaction support
   */
  async create(
    request: CreateTermsAgreementRequest,
    client?: PoolClient
  ): Promise<TermsAgreement> {
    const query = `
      INSERT INTO terms_agreements (
        user_id, ip_address, user_agent,
        terms_version, terms_url, terms_content_hash
      )
      VALUES ($1, $2, $3, $4, $5, $6)
      RETURNING ${TERMS_AGREEMENT_COLUMNS}
    `;

    const values = [
      request.userId,
      request.ipAddress,
      request.userAgent,
      request.termsVersion,
      request.termsUrl,
      request.termsContentHash,
    ];

    try {
      const executor = client || this.pool;
      const result = await executor.query(query, values);

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

      return this.mapRow(result.rows[0]);
    } catch (error) {
      logger.error('Error creating terms agreement', { error, userId: request.userId });
      throw error;
    }
  }

  /**
   * Get terms agreement by user ID
   */
  async getByUserId(userId: string): Promise<TermsAgreement | null> {
    const query = `
      SELECT ${TERMS_AGREEMENT_COLUMNS}
      FROM terms_agreements
      WHERE user_id = $1
      ORDER BY agreed_at DESC
      LIMIT 1
    `;

    try {
      const result = await this.pool.query(query, [userId]);
      if (result.rows.length === 0) {
        return null;
      }
      return this.mapRow(result.rows[0]);
    } catch (error) {
      logger.error('Error fetching terms agreement by user_id', { error, userId });
      throw error;
    }
  }

  private mapRow(row: any): TermsAgreement {
    return {
      id: row.id,
      userId: row.user_id,
      agreedAt: new Date(row.agreed_at),
      ipAddress: row.ip_address,
      userAgent: row.user_agent,
      termsVersion: row.terms_version,
      termsUrl: row.terms_url,
      termsContentHash: row.terms_content_hash,
      createdAt: new Date(row.created_at),
      updatedAt: new Date(row.updated_at),
    };
  }
}
