import { OAuth2Client } from 'google-auth-library'
import { authPool } from '../db/authDb.js'
import { signToken, setTokenCookie } from './jwtProvider.js'
import { getSetting } from '../settings/settingsService.js'
import { AuthError, getUserInfo } from './authService.js'
import type { Response } from 'express'

const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID || ''
const googleClient = new OAuth2Client(GOOGLE_CLIENT_ID)

interface GoogleProfile {
  sub: string
  email: string
  name: string
  picture?: string
  hd?: string // hosted domain (Google Workspace)
}

export interface GoogleLoginResult {
  type: 'success' | 'pending'
  user?: Awaited<ReturnType<typeof getUserInfo>>
  message?: string
}

export async function googleLogin(
  credential: string,
  ipAddr: string,
  userAgent: string,
  res: Response
): Promise<GoogleLoginResult> {
  const profile = await verifyGoogleToken(credential)

  // 1. OAUTH_SUB로 기존 사용자 조회
  let userResult = await authPool.query(
    'SELECT USER_ID as user_id, USER_STTS_CD as user_stts_cd FROM AUTH_USER WHERE OAUTH_PROVIDER = $1 AND OAUTH_SUB = $2',
    ['GOOGLE', profile.sub]
  )

  let userId: string

  if (userResult.rows.length > 0) {
    // 기존 OAuth 사용자
    const user = userResult.rows[0]
    userId = user.user_id

    if (user.user_stts_cd === 'PENDING') {
      return { type: 'pending', message: '계정이 승인 대기 중입니다. 관리자 승인 후 로그인할 수 있습니다.' }
    }
    if (user.user_stts_cd === 'LOCKED') {
      throw new AuthError('계정이 잠겨있습니다. 관리자에게 문의하세요.', 403)
    }
    if (user.user_stts_cd === 'INACTIVE') {
      throw new AuthError('비활성화된 계정입니다.', 403)
    }
    if (user.user_stts_cd === 'REJECTED') {
      throw new AuthError('가입이 거절된 계정입니다. 관리자에게 문의하세요.', 403)
    }
  } else {
    // EMAIL로 기존 PW 사용자 조회 (계정 연결)
    userResult = await authPool.query(
      'SELECT USER_ID as user_id, USER_STTS_CD as user_stts_cd FROM AUTH_USER WHERE EMAIL = $1 OR USER_ACNT = $1',
      [profile.email]
    )

    if (userResult.rows.length > 0) {
      // 기존 계정에 OAuth 연결
      const user = userResult.rows[0]
      userId = user.user_id

      await authPool.query(
        'UPDATE AUTH_USER SET OAUTH_PROVIDER = $1, OAUTH_SUB = $2, EMAIL = $3, MDFCN_DTM = NOW() WHERE USER_ID = $4',
        ['GOOGLE', profile.sub, profile.email, userId]
      )

      if (user.user_stts_cd === 'PENDING') {
        return { type: 'pending', message: '계정이 승인 대기 중입니다. 관리자 승인 후 로그인할 수 있습니다.' }
      }
      if (user.user_stts_cd !== 'ACTIVE') {
        throw new AuthError('계정이 활성 상태가 아닙니다. 관리자에게 문의하세요.', 403)
      }
    } else {
      // 신규 사용자 생성
      userId = await createOAuthUser(profile)

      // PENDING 상태로 생성된 경우 등록 완료 안내
      const statusResult = await authPool.query(
        'SELECT USER_STTS_CD as user_stts_cd FROM AUTH_USER WHERE USER_ID = $1',
        [userId]
      )
      if (statusResult.rows[0]?.user_stts_cd === 'PENDING') {
        return { type: 'pending', message: '계정이 등록되었습니다. 관리자 승인 후 로그인할 수 있습니다.' }
      }
    }
  }

  // ACTIVE 사용자 로그인 처리
  await authPool.query(
    'UPDATE AUTH_USER SET LAST_LOGIN_DTM = NOW(), MDFCN_DTM = NOW() WHERE USER_ID = $1',
    [userId]
  )

  await recordLoginHistory(userId, ipAddr, userAgent)

  const userInfo = await getUserInfo(userId)

  const token = signToken({
    sub: userInfo.id,
    acnt: userInfo.account,
    name: userInfo.name,
    roles: userInfo.roles,
  })

  setTokenCookie(res, token)
  return { type: 'success', user: userInfo }
}

async function verifyGoogleToken(credential: string): Promise<GoogleProfile> {
  try {
    const ticket = await googleClient.verifyIdToken({
      idToken: credential,
      audience: GOOGLE_CLIENT_ID,
    })

    const payload = ticket.getPayload()
    if (!payload || !payload.email || !payload.sub) {
      throw new AuthError('Google 인증 정보가 유효하지 않습니다.', 401)
    }

    return {
      sub: payload.sub,
      email: payload.email,
      name: payload.name || payload.email.split('@')[0],
      picture: payload.picture,
      hd: payload.hd,
    }
  } catch (err) {
    if (err instanceof AuthError) throw err
    throw new AuthError('Google 인증 토큰 검증에 실패했습니다.', 401)
  }
}

async function createOAuthUser(profile: GoogleProfile): Promise<string> {
  const domain = profile.email.split('@')[1]

  // 자동 승인 도메인 확인
  const autoApproveDomains = await getSetting('oauth.auto-approve-domains')
  const allowedDomains = autoApproveDomains
    ? autoApproveDomains.split(',').map(d => d.trim().toLowerCase())
    : []

  const isAutoApproved = allowedDomains.includes(domain.toLowerCase())
  const status = isAutoApproved ? 'ACTIVE' : 'PENDING'

  // 사용자 생성
  const result = await authPool.query(
    `INSERT INTO AUTH_USER (USER_ACNT, USER_NM, EMAIL, OAUTH_PROVIDER, OAUTH_SUB, USER_STTS_CD)
     VALUES ($1, $2, $3, $4, $5, $6) RETURNING USER_ID as user_id`,
    [profile.email, profile.name, profile.email, 'GOOGLE', profile.sub, status]
  )

  const userId = result.rows[0].user_id

  // 자동 승인된 사용자에게 기본 역할 할당
  if (isAutoApproved) {
    await authPool.query(
      `INSERT INTO AUTH_USER_ROLE (USER_ID, ROLE_SN)
       SELECT $1, ROLE_SN FROM AUTH_ROLE WHERE DFLT_YN = 'Y'`,
      [userId]
    )
  }

  return userId
}

async function recordLoginHistory(
  userId: string,
  ipAddr: string,
  userAgent: string
): Promise<void> {
  await authPool.query(
    `INSERT INTO AUTH_LOGIN_HIST (USER_ID, IP_ADDR, USER_AGENT, SUCCESS_YN)
     VALUES ($1, $2, $3, 'Y')`,
    [userId, ipAddr, userAgent?.substring(0, 500)]
  )
}
