/**
 * Phoenix Identity Service (Sovereign Stack)
 * Extends the base identity service with marketplace-specific features
 * Users, orgs, roles, permissions, device binding, passkeys, OAuth/OIDC
 */

import { getDb } from '../../db/index.js'
import { logger } from '../../lib/logger.js'
import { identityService } from '../identity.js'

export interface User {
  userId: string
  email: string
  name: string
  roles: string[]
  permissions: Record<string, any>
  orgId: string | null
}

export interface Organization {
  orgId: string
  name: string
  domain: string | null
  status: 'ACTIVE' | 'SUSPENDED'
}

export interface DeviceBinding {
  deviceId: string
  userId: string
  deviceType: string
  fingerprint: string
  lastUsed: Date
}

class SovereignIdentityService {
  /**
   * Create user
   */
  async createUser(
    email: string,
    name: string,
    orgId?: string
  ): Promise<User> {
    const db = getDb()
    
    // Use base identity service for Keycloak integration
    const keycloakUser = await identityService.createUser(email, name)
    
    // Store in local DB for marketplace features
    const result = await db.query(
      `INSERT INTO marketplace_users (user_id, email, name, org_id)
       VALUES ($1, $2, $3, $4)
       ON CONFLICT (user_id) DO UPDATE SET
         email = EXCLUDED.email,
         name = EXCLUDED.name,
         org_id = EXCLUDED.org_id
       RETURNING *`,
      [keycloakUser.id, email, name, orgId || null]
    )

    return this.mapUser(result.rows[0])
  }

  /**
   * Create organization
   */
  async createOrganization(
    name: string,
    domain?: string
  ): Promise<Organization> {
    const db = getDb()
    
    const result = await db.query(
      `INSERT INTO organizations (name, domain, status)
       VALUES ($1, $2, 'ACTIVE')
       RETURNING *`,
      [name, domain || null]
    )

    logger.info('Organization created', { orgId: result.rows[0].id })
    return this.mapOrganization(result.rows[0])
  }

  /**
   * Bind device to user
   */
  async bindDevice(
    userId: string,
    deviceType: string,
    fingerprint: string
  ): Promise<DeviceBinding> {
    const db = getDb()
    
    const result = await db.query(
      `INSERT INTO device_bindings (user_id, device_type, fingerprint, last_used)
       VALUES ($1, $2, $3, NOW())
       ON CONFLICT (user_id, fingerprint) DO UPDATE SET
         last_used = NOW()
       RETURNING *`,
      [userId, deviceType, fingerprint]
    )

    logger.info('Device bound', { deviceId: result.rows[0].id, userId })
    return this.mapDeviceBinding(result.rows[0])
  }

  /**
   * Get user with roles and permissions
   */
  async getUser(userId: string): Promise<User | null> {
    const db = getDb()
    
    const result = await db.query(
      `SELECT 
        u.*,
        o.org_id,
        ARRAY_AGG(DISTINCT r.role_name) as roles,
        jsonb_object_agg(DISTINCT p.permission_key, p.permission_value) as permissions
      FROM marketplace_users u
      LEFT JOIN organizations o ON u.org_id = o.id
      LEFT JOIN user_roles r ON u.user_id = r.user_id
      LEFT JOIN user_permissions p ON u.user_id = p.user_id
      WHERE u.user_id = $1
      GROUP BY u.user_id, o.org_id`,
      [userId]
    )

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

    return this.mapUser(result.rows[0])
  }

  /**
   * Assign role to user
   */
  async assignRole(userId: string, roleName: string): Promise<void> {
    const db = getDb()
    
    await db.query(
      `INSERT INTO user_roles (user_id, role_name)
       VALUES ($1, $2)
       ON CONFLICT (user_id, role_name) DO NOTHING`,
      [userId, roleName]
    )

    logger.info('Role assigned', { userId, roleName })
  }

  private mapUser(row: any): User {
    return {
      userId: row.user_id,
      email: row.email,
      name: row.name,
      roles: row.roles || [],
      permissions: row.permissions || {},
      orgId: row.org_id
    }
  }

  private mapOrganization(row: any): Organization {
    return {
      orgId: row.id,
      name: row.name,
      domain: row.domain,
      status: row.status
    }
  }

  private mapDeviceBinding(row: any): DeviceBinding {
    return {
      deviceId: row.id,
      userId: row.user_id,
      deviceType: row.device_type,
      fingerprint: row.fingerprint,
      lastUsed: row.last_used
    }
  }
}

export const sovereignIdentityService = new SovereignIdentityService()
