import { NextAuthOptions } from 'next-auth'
import CredentialsProvider from 'next-auth/providers/credentials'
import { JWT } from 'next-auth/jwt'

declare module 'next-auth' {
  interface Session {
    user: {
      name?: string | null
      surname?: string | null
      email?: string | null
      phone_number?: string | null
      image?: string | null
    }
    accessToken?: string
    refreshToken?: string
    expiresAt?: number
  }

  interface User {
    id: string
    email: string
    name?: string
    accessToken?: string
    refreshToken?: string
  }

  interface JWT {
    accessToken?: string
    refreshToken?: string
    expiresAt?: number
    error?: string
  }
}

interface GoogleToken extends JWT {
  accessToken?: string
  refreshToken?: string
  expiresAt?: number | undefined
  error?: string
}

async function refreshAccessToken(token: GoogleToken): Promise<GoogleToken> {
  try {
    const BACKEND = process.env.BACKEND_URL || 'http://127.0.0.1:8000/api/v1'
    const response = await fetch(`${BACKEND}/auth/refresh/`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        refresh: token.refreshToken,
      }),
    })

    if (!response.ok) {
      const errorText = await response.text()
      let errorData: { error?: string; [key: string]: unknown } = {}
      try {
        errorData = JSON.parse(errorText)
      } catch {
        errorData = { error: errorText }
      }
        
      const errorMessage = (errorData.error as string) || (errorData.detail as string) || ''
      if (typeof errorMessage === 'string' && 
          (errorMessage.includes('Token is expired') || 
           errorMessage.includes('expired') || 
           errorData.code === 'token_not_valid')) {
        console.warn('Refresh token expired, user needs to re-authenticate')
        return {
          ...token,
          error: 'RefreshTokenExpired',
        }
      }
      
      console.error('Token refresh failed:', errorData.error || 'Token refresh failed')
      return {
        ...token,
        error: 'RefreshAccessTokenError',
      }
    }

    const refreshedTokens = await response.json()

    return {
      ...token,
      accessToken: refreshedTokens.access,
      refreshToken: refreshedTokens.refresh ?? token.refreshToken,
      expiresAt: refreshedTokens.expires_at,
    }
  } catch (error) {
    console.error('Refresh error:', error)
    return {
      ...token,
      error: 'RefreshAccessTokenError',
    }
  }
}

export const authOptions: NextAuthOptions = {
  providers: [
    //логин
    CredentialsProvider({
      id: 'credentials',
      name: 'Credentials',
      credentials: {
        login: { label: 'Login', type: 'text' },
        password: { label: 'Password', type: 'password' },
        role: { label: 'Role', type: 'text' },
      },
      async authorize(credentials) {
        try {
          const BACKEND = process.env.BACKEND_URL || 'http://127.0.0.1:8000/api/v1'
          const res = await fetch(`${BACKEND}/auth/login/`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
              login: credentials?.login,
              password: credentials?.password,
              role: credentials?.role,
            }),
          })

          const raw = await res.text()
          let data: {
            error?: string
            user?: {
              id: string | number
              email: string
              name: string
              role: string
            }
            access?: string
            refresh?: string
            [key: string]: unknown
          }
          try {
            data = JSON.parse(raw)
          } catch {
            data = { error: raw }
          }

          if (!res.ok) {
            throw new Error(data.error || `Authentication failed (${res.status})`)
          }

          return {
            id: data.user?.id?.toString?.() ?? String(data.user?.id),
            email: data.user?.email ?? '',
            name: data.user?.name ?? '', // backend uses `name`, not `firstName`
            accessToken: data.access ?? '',
            refreshToken: data.refresh ?? '',
          }
        } catch (error) {
          console.error('Login error:', error)
          return null
        }
      },
    }),
  ],
  callbacks: {
    async jwt({ token, user, account }) {
      if (user && account) {
        if (account.type === 'credentials') {
          return {
            ...token,
            accessToken: user.accessToken,
            refreshToken: user.refreshToken,
            expiresAt: Math.floor(Date.now() / 1000) + 15 * 60, // 15 минут
          }
        } else {
          return {
            ...token,
            accessToken: account.access_token,
            refreshToken: account.refresh_token,
            expiresAt: account.expires_at,
          }
        }
      }

      // проверяем не истекает ли токен в ближайшие 5 минут
      const expiresAt = token.expiresAt as number | undefined
      if (
        typeof expiresAt === 'number' &&
        Date.now() < (expiresAt - 5 * 60) * 1000 // обновляем за 5 минут до истечения
      ) {
        return token
      }

      return refreshAccessToken(token as GoogleToken)
    },
    async session({ session, token }) {
      if (token) {
        session.accessToken = token.accessToken as string
        session.refreshToken = token.refreshToken as string
         
        if (token.error === 'RefreshTokenExpired') {
          session.accessToken = undefined
          session.refreshToken = undefined
        }
      }
      return session
    },
  },
}
