import { betterAuth } from 'better-auth';
import { sso } from '@better-auth/sso';
import { oidcProvider } from 'better-auth/plugins';
import { credentials } from 'better-auth-credentials-plugin';
import { authenticate } from 'ldap-authentication';
import { z } from 'zod';
import { db } from './db';

const baseUrl = process.env.BETTER_AUTH_URL || 'http://localhost:3001';

export const auth = betterAuth({
  database: db,
  basePath: '/api/auth',
  baseURL: baseUrl,
  trustedOrigins: [
    baseUrl,
    'http://localhost:3000',
    'http://localhost:3001',
    ...(process.env.TRUSTED_ORIGINS || '').split(',').filter(Boolean),
  ],
  emailAndPassword: {
    enabled: true,
  },
  plugins: [
    // SSO — вход через внешние IdP (Okta, Google, Azure AD)
    sso(),

    // OIDC Provider — этот сервис выступает как IdP для других приложений
    oidcProvider({
      loginPage: '/sign-in',
      allowDynamicClientRegistration: true,
      trustedClients: (() => {
        try {
          if (process.env.TRUSTED_CLIENTS) {
            return JSON.parse(process.env.TRUSTED_CLIENTS);
          }
        } catch {
          /* ignore */
        }
        return [
            {
              clientId: process.env.DEFAULT_CLIENT_ID || 'perplexica',
              clientSecret: process.env.DEFAULT_CLIENT_SECRET || 'perplexica-secret-change-me',
              name: 'Perplexica',
              type: 'web',
              redirectUrls: ['http://localhost:3000/api/auth/callback/better-auth'],
              disabled: false,
              skipConsent: true,
            },
          ];
      })(),
    }),

    // LDAP — вход через Active Directory / OpenLDAP
    ...(process.env.LDAP_URL
      ? [
          credentials({
            autoSignUp: true,
            linkAccountIfExisting: true,
            providerId: 'ldap',
            path: '/sign-in/ldap',
            inputSchema: z.object({
              credential: z.string().min(1, 'Username or DN required'),
              password: z.string().min(1, 'Password required'),
            }),
            async callback(_ctx, parsed) {
              const ldapResult = await authenticate({
                ldapOpts: {
                  url: process.env.LDAP_URL!,
                  connectTimeout: 5000,
                  ...(process.env.LDAP_URL!.startsWith('ldaps://')
                    ? { tlsOptions: { minVersion: 'TLSv1.2' } }
                    : {}),
                },
                adminDn: process.env.LDAP_BIND_DN || '',
                adminPassword: process.env.LDAP_PASSWORD || '',
                userSearchBase: process.env.LDAP_BASE_DN || '',
                usernameAttribute: process.env.LDAP_USERNAME_ATTR || 'uid',
                username: parsed.credential,
                userPassword: parsed.password,
              });

              const uid = ldapResult[process.env.LDAP_USERNAME_ATTR || 'uid'];
              const email =
                (Array.isArray(ldapResult.mail) ? ldapResult.mail[0] : ldapResult.mail) ||
                `${uid}@local`;

              return {
                email,
                name: ldapResult.displayName || ldapResult.cn || String(uid),
              };
            },
          }),
        ]
      : []),
  ],
});
