import Foundation
import XCTest

/// High-level account lifecycle management for UI tests.
enum TestAccountManager {

    // MARK: - Credential Generation

    /// Generate unique credentials with a timestamp + random suffix to avoid collisions.
    static func uniqueCredentials(prefix: String = "uit") -> (username: String, email: String, password: String) {
        let stamp = Int(Date().timeIntervalSince1970)
        let random = Int.random(in: 1000...9999)
        let username = "\(prefix)_\(stamp)_\(random)"
        let email = "\(username)@test.example.com"
        let password = "Pass\(stamp)!"
        return (username, email, password)
    }

    // MARK: - Account Creation

    /// Create a verified account via the backend API. Returns a ready-to-use session.
    /// Calls `XCTFail` and returns nil if any step fails.
    static func createVerifiedAccount(
        file: StaticString = #filePath,
        line: UInt = #line
    ) -> TestSession? {
        let creds = uniqueCredentials()

        guard let session = TestAccountAPIClient.createVerifiedAccount(
            username: creds.username,
            email: creds.email,
            password: creds.password
        ) else {
            XCTFail("Failed to create verified account for \(creds.username)", file: file, line: line)
            return nil
        }

        return session
    }

    /// Create an unverified account (register only, no email verification).
    /// Useful for testing the verification gate.
    static func createUnverifiedAccount(
        file: StaticString = #filePath,
        line: UInt = #line
    ) -> TestSession? {
        let creds = uniqueCredentials()

        guard let response = TestAccountAPIClient.register(
            username: creds.username,
            email: creds.email,
            password: creds.password
        ) else {
            XCTFail("Failed to register unverified account for \(creds.username)", file: file, line: line)
            return nil
        }

        return TestSession(
            token: response.token,
            user: response.user,
            username: creds.username,
            password: creds.password
        )
    }

    // MARK: - Seeded Accounts

    /// Login with a pre-seeded account that already exists in the database.
    static func loginSeededAccount(
        username: String = "admin",
        password: String = "Test1234",
        file: StaticString = #filePath,
        line: UInt = #line
    ) -> TestSession? {
        guard let response = TestAccountAPIClient.login(username: username, password: password) else {
            XCTFail("Failed to login seeded account '\(username)'", file: file, line: line)
            return nil
        }

        return TestSession(
            token: response.token,
            user: response.user,
            username: username,
            password: password
        )
    }

    // MARK: - Password Reset

    /// Execute the full forgot→verify→reset cycle via the backend API.
    static func resetPassword(
        email: String,
        newPassword: String,
        file: StaticString = #filePath,
        line: UInt = #line
    ) -> Bool {
        guard TestAccountAPIClient.forgotPassword(email: email) != nil else {
            XCTFail("Forgot password request failed for \(email)", file: file, line: line)
            return false
        }

        guard let verifyResponse = TestAccountAPIClient.verifyResetCode(email: email) else {
            XCTFail("Verify reset code failed for \(email)", file: file, line: line)
            return false
        }

        guard TestAccountAPIClient.resetPassword(resetToken: verifyResponse.resetToken, newPassword: newPassword) != nil else {
            XCTFail("Reset password failed for \(email)", file: file, line: line)
            return false
        }

        return true
    }

    // MARK: - Token Management

    /// Invalidate a session token via the logout API.
    static func invalidateToken(
        _ session: TestSession,
        file: StaticString = #filePath,
        line: UInt = #line
    ) {
        if TestAccountAPIClient.logout(token: session.token) == nil {
            XCTFail("Failed to invalidate token for \(session.username)", file: file, line: line)
        }
    }
}
