import type { BetterAuthInstance } from './better-auth-config.js';
import type { FastifyBaseLogger } from 'fastify';
import type { Pool } from 'pg';
import { LICENSE_TIER_TEMPLATES } from '../types/user.js';

export interface AuthServiceConfig {
  auth: BetterAuthInstance;
  pool: Pool;
  logger: FastifyBaseLogger;
}

/**
 * Authentication service that integrates Better Auth with existing user system
 */
export class AuthService {
  private config: AuthServiceConfig;

  constructor(config: AuthServiceConfig) {
    this.config = config;
  }

  /**
   * Verify session token and return user ID
   * Uses Better Auth's bearer plugin for token verification
   */
  async verifyToken(token: string): Promise<string | null> {
    try {
      this.config.logger.debug({
        tokenLength: token?.length,
        tokenPrefix: token?.substring(0, 8),
      }, 'Verifying token');

      // Use Better Auth's getSession with Bearer token
      // The bearer plugin allows us to pass the session token via Authorization header
      const session = await this.config.auth.api.getSession({
        headers: new Headers({
          'Authorization': `Bearer ${token}`,
        }),
      });

      this.config.logger.debug({
        hasSession: !!session,
        hasUser: !!session?.user,
        userId: session?.user?.id,
      }, 'Session verification result');

      if (!session || !session.user) {
        this.config.logger.warn('Session verification failed: no session or user');
        return null;
      }

      return session.user.id;
    } catch (error) {
      this.config.logger.error({ error }, 'Token verification failed with error');
      return null;
    }
  }

  /**
   * Create user with email and password
   */
  async createUser(email: string, password: string, name?: string): Promise<{ userId: string; error?: string }> {
    try {
      const result = await this.config.auth.api.signUpEmail({
        body: {
          email,
          password,
          name: name || email.split('@')[0],
        },
      });

      if (!result.user) {
        return {
          userId: '',
          error: 'Failed to create user',
        };
      }

      return {
        userId: result.user.id,
      };
    } catch (error: any) {
      this.config.logger.error({ error }, 'User creation failed');
      return {
        userId: '',
        error: error.message || 'User creation failed',
      };
    }
  }

  /**
   * Sign in with email and password
   * Returns the bearer token from response headers
   */
  async signIn(email: string, password: string): Promise<{ token: string; userId: string; error?: string }> {
    try {
      this.config.logger.debug({ email }, 'Attempting sign in');

      // Use asResponse: true to get the full Response object with headers
      const response = await this.config.auth.api.signInEmail({
        body: {
          email,
          password,
        },
        asResponse: true,
      });

      // Extract bearer token from response headers (set by bearer plugin)
      const token = response.headers.get('set-auth-token');

      if (!token) {
        this.config.logger.error('Bearer token not found in response headers');
        return {
          token: '',
          userId: '',
          error: 'Authentication token not generated',
        };
      }

      // Parse the response body to get user info
      const result = await response.json() as {
        user?: { id: string; email: string; name: string };
        error?: string;
      };

      this.config.logger.debug({
        hasUser: !!result.user,
        userId: result.user?.id,
        hasToken: !!token,
      }, 'Sign in result');

      if (!result.user) {
        this.config.logger.warn('Sign in failed: no user in result');
        return {
          token: '',
          userId: '',
          error: 'Invalid credentials',
        };
      }

      return {
        token,
        userId: result.user.id,
      };
    } catch (error: any) {
      this.config.logger.error({ error }, 'Sign in failed with error');
      return {
        token: '',
        userId: '',
        error: error.message || 'Sign in failed',
      };
    }
  }

  /**
   * Sign out and invalidate session
   */
  async signOut(token: string): Promise<{ success: boolean }> {
    try {
      await this.config.auth.api.signOut({
        headers: {
          // Better Auth expects the session token in the cookie header
          cookie: `better-auth.session_token=${token}`,
        },
      });

      return { success: true };
    } catch (error) {
      this.config.logger.error({ error }, 'Sign out failed');
      return { success: false };
    }
  }

  /**
   * Get current session from token
   */
  async getSession(token: string) {
    try {
      const session = await this.config.auth.api.getSession({
        headers: new Headers({
          'Authorization': `Bearer ${token}`,
        }),
      });

      return session;
    } catch (error) {
      this.config.logger.debug({ error }, 'Get session failed');
      return null;
    }
  }

  /**
   * Ensure user has a license (create default license if needed)
   */
  async ensureUserLicense(userId: string, email: string): Promise<void> {
    const client = await this.config.pool.connect();
    try {
      // Check if license exists
      const licenseCheck = await client.query(
        'SELECT user_id FROM user_licenses WHERE user_id = $1',
        [userId]
      );

      if (licenseCheck.rows.length === 0) {
        // Create default free license — copy the full tier template so every field is present
        await client.query(
          `INSERT INTO user_licenses (user_id, email, license, mcp_server_url)
           VALUES ($1, $2, $3::jsonb, 'pending')`,
          [userId, email, JSON.stringify(LICENSE_TIER_TEMPLATES.free)]
        );

        this.config.logger.info({ userId }, 'Created default free license for new user');
      }
    } finally {
      client.release();
    }
  }
}
