import type { Context } from 'hono';
import { SessionManager } from './session-manager';
import { CookieUtils } from './utils/cookie-utils';
import { HtmlTemplates, type PageConfig } from './utils/html-templates';
import { OIDCProviderConfig, PasswordValidator, AuthorizationRequest, LoginCredentials } from '../types';

/**
 * 认证结果接口
 */
export interface AuthenticationResult {
    /** 是否认证成功 */
    success: boolean;
    /** 用户ID（认证成功时） */
    userId?: string;
    /** 错误信息（认证失败时） */
    error?: string;
    /** 附加数据 */
    metadata?: Record<string, any>;
}

/**
 * 密码认证策略配置
 */
export interface PasswordAuthConfig {
    /** 会话TTL（秒） */
    sessionTTL?: number;
    /** 页面配置 */
    pageConfig?: PageConfig;
    /** 记住我功能的最大时长（秒） */
    rememberMeMaxAge?: number;
}

/**
 * 密码认证策略
 * 实现基于用户名和密码的传统认证方式
 */
export class PasswordAuth {
    readonly name = 'password';

    private readonly sessionManager: SessionManager;
    private readonly config: {
        sessionTTL: number;
        rememberMeMaxAge: number;
        pageConfig?: PageConfig;
    };

    constructor(
        private readonly oidcConfig: OIDCProviderConfig,
        private readonly passwordValidator: PasswordValidator,
        config: PasswordAuthConfig = {}
    ) {
        this.config = {
            sessionTTL: 24 * 60 * 60, // 24小时
            rememberMeMaxAge: 30 * 24 * 60 * 60, // 30天
            ...config
        };
        this.sessionManager = new SessionManager(oidcConfig.storage, this.config.sessionTTL);
    }

    /**
     * 检查当前用户是否已认证
     */
    async getCurrentUser(c: Context): Promise<string | null> {
        const sessionId = CookieUtils.getSessionIdFromCookie(c);
        if (!sessionId) return null;

        try {
            const session = await this.sessionManager.getSession(sessionId);
            return session?.user_id || null;
        } catch (error) {
            console.error('获取会话失败:', error);
            return null;
        }
    }

    /**
     * 处理认证要求 - 显示登录页面
     */
    async handleAuthenticationRequired(c: Context, authRequest: AuthorizationRequest): Promise<Response> {
        const loginHtml = HtmlTemplates.generateLoginPage(authRequest, this.config.pageConfig);
        c.header('Content-Type', 'text/html; charset=utf-8');
        return c.body(loginHtml);
    }

    /**
     * 处理认证请求
     */
    async authenticate(c: Context): Promise<AuthenticationResult> {
        try {
            const formData = await c.req.formData();
            const credentials = this.parseCredentials(formData);
            const authParams = this.extractAuthParams(formData);

            // 验证输入
            const validationError = this.validateCredentials(credentials);
            if (validationError) {
                return { success: false, error: validationError };
            }

            // 验证用户密码
            const userId = await this.passwordValidator(credentials.username, credentials.password);
            if (!userId) {
                return { success: false, error: '用户名或密码错误' };
            }

            // 检查用户是否存在
            const user = await this.oidcConfig.findUser(userId);
            if (!user) {
                return { success: false, error: '用户不存在' };
            }

            // 创建会话
            const session = await this.sessionManager.createSession(userId, authParams.client_id, authParams);

            const maxAge = credentials.remember_me
                ? this.config.rememberMeMaxAge
                : this.config.sessionTTL;

            return {
                success: true,
                userId,
                metadata: {
                    sessionId: session.session_id,
                    maxAge,
                    authParams,
                    rememberMe: credentials.remember_me
                }
            };
        } catch (error) {
            console.error('认证处理失败:', error);
            return { success: false, error: '服务器内部错误，请稍后重试' };
        }
    }

    /**
     * 处理登出请求
     */
    async logout(c: Context): Promise<Response> {
        const sessionId = CookieUtils.getSessionIdFromCookie(c);

        if (sessionId) {
            try {
                await this.sessionManager.destroySession(sessionId);
            } catch (error) {
                console.error('销毁会话失败:', error);
            }
        }

        CookieUtils.clearSessionCookie(c);

        const postLogoutRedirectUri = c.req.query('post_logout_redirect_uri');
        const state = c.req.query('state');

        if (postLogoutRedirectUri) {
            const redirectUrl = this.buildPostLogoutRedirectUrl(postLogoutRedirectUri, state);
            return c.redirect(redirectUrl);
        }

        return c.json({
            message: '已成功登出',
            timestamp: new Date().toISOString()
        });
    }

    /**
     * 处理认证成功后的操作
     */
    async handleAuthenticationSuccess(c: Context, result: AuthenticationResult): Promise<Response> {
        if (!result.success || !result.metadata) {
            throw new Error('认证结果无效');
        }

        const { sessionId, maxAge, authParams } = result.metadata;

        CookieUtils.setSessionCookie(c, sessionId, maxAge);
        const authUrl = this.buildAuthorizationUrl(authParams);
        return c.redirect(authUrl);
    }

    /**
     * 处理认证失败后的操作
     */
    async handleAuthenticationFailure(
        c: Context,
        result: AuthenticationResult,
        authRequest: AuthorizationRequest
    ): Promise<Response> {
        const errorHtml = HtmlTemplates.generateLoginPage(authRequest, this.config.pageConfig, result.error);
        c.header('Content-Type', 'text/html; charset=utf-8');
        return c.body(errorHtml);
    }

    /**
     * 解析登录凭据
     */
    private parseCredentials(formData: FormData): LoginCredentials {
        return {
            username: formData.get('username')?.toString() || '',
            password: formData.get('password')?.toString() || '',
            remember_me: formData.get('remember_me') === 'on',
        };
    }

    /**
     * 验证登录凭据
     */
    private validateCredentials(credentials: LoginCredentials): string | null {
        if (!credentials.username.trim()) return '请输入用户名';
        if (!credentials.password) return '请输入密码';
        if (credentials.username.length > 100) return '用户名过长';
        if (credentials.password.length > 200) return '密码过长';
        return null;
    }

    /**
     * 构建登出后重定向URL
     */
    private buildPostLogoutRedirectUrl(redirectUri: string, state?: string): string {
        if (!state) return redirectUri;

        const url = new URL(redirectUri);
        url.searchParams.set('state', state);
        return url.toString();
    }

    /**
     * 构建授权URL
     */
    private buildAuthorizationUrl(authParams: AuthorizationRequest): string {
        const params = new URLSearchParams();
        params.set('response_type', authParams.response_type);
        params.set('client_id', authParams.client_id);
        params.set('redirect_uri', authParams.redirect_uri);
        params.set('scope', authParams.scope);

        if (authParams.state) params.set('state', authParams.state);
        if (authParams.nonce) params.set('nonce', authParams.nonce);
        if (authParams.code_challenge) params.set('code_challenge', authParams.code_challenge);
        if (authParams.code_challenge_method) params.set('code_challenge_method', authParams.code_challenge_method);

        return `/oidc/auth?${params.toString()}`;
    }

    /**
     * 从表单数据提取授权参数
     */
    private extractAuthParams(formData: FormData): AuthorizationRequest {
        return {
            response_type: formData.get('response_type')?.toString() || '',
            client_id: formData.get('client_id')?.toString() || '',
            redirect_uri: formData.get('redirect_uri')?.toString() || '',
            scope: formData.get('scope')?.toString() || '',
            state: formData.get('state')?.toString(),
            nonce: formData.get('nonce')?.toString(),
            code_challenge: formData.get('code_challenge')?.toString(),
            code_challenge_method: formData.get('code_challenge_method')?.toString() as 'plain' | 'S256' | undefined,
        };
    }
} 