import Foundation
import SwiftUI
import Combine

@MainActor
class PDSViewModel: ObservableObject {
    @Published var pdsService = PDSService()
    @Published var alertItem: AlertItem?
    @Published var demoMode: Bool = false
    
    // Mock data for demo mode
    private var mockUsers: [PDSUser] = []
    private var mockInviteCodes: [InviteCode] = []
    
    var errorMessage: String? {
        pdsService.errorMessage
    }
    
    var isLoading: Bool {
        pdsService.isLoading
    }
    
    var isAuthenticated: Bool {
        get {
            if demoMode {
                return true // Always authenticated in demo mode
            }
            let value = pdsService.isAuthenticated
            print("PDSViewModel: isAuthenticated getter called, value = \(value)")
            return value
        }
    }
    
    var users: [PDSUser] {
        if demoMode {
            return mockUsers
        }
        return pdsService.users
    }
    
    var inviteCodes: [InviteCode] {
        if demoMode {
            return mockInviteCodes
        }
        return pdsService.inviteCodes
    }
    
    // Add listeners for PDSService changes
    init() {
        // Subscribe to PDSService objectWillChange events
        pdsService.objectWillChange.sink { [weak self] _ in
            // Forward the change notification to our own objectWillChange
            DispatchQueue.main.async {
                self?.objectWillChange.send()
            }
        }
        .store(in: &cancellables)
    }
    
    // Storage for cancellables
    private var cancellables = Set<AnyCancellable>()
    
    // Method to manually refresh UI data
    func refreshUI() {
        print("PDSViewModel: refreshUI called")
        DispatchQueue.main.async {
            print("PDSViewModel: sending objectWillChange notification")
            self.objectWillChange.send()
            
            if self.demoMode {
                print("Demo users status: \(self.mockUsers.map { "\($0.handle): \($0.isActive)" }.joined(separator: ", "))")
            }
        }
    }
    
    // Enable demo mode with mock data
    func enableDemoMode() {
        demoMode = true
        createMockData()
        refreshUI()
    }
    
    // Disable demo mode
    func disableDemoMode() {
        demoMode = false
        refreshUI()
    }
    
    // Create mock data for demo mode
    private func createMockData() {
        // Create mock users
        mockUsers = [
            PDSUser(
                id: "did:plc:abcdef123456",
                handle: "alice",
                displayName: "Alice Smith",
                description: "Product designer and developer. Working on decentralized social apps.",
                joinedAt: Date().addingTimeInterval(-86400 * 30), // 30 days ago
                avatar: nil,
                isActive: true
            ),
            PDSUser(
                id: "did:plc:ghijkl789012",
                handle: "bob",
                displayName: "Bob Johnson",
                description: "Software engineer. Interested in decentralized protocols and privacy.",
                joinedAt: Date().addingTimeInterval(-86400 * 15), // 15 days ago
                avatar: nil,
                isActive: true
            ),
            PDSUser(
                id: "did:plc:mnopqr345678",
                handle: "charlie",
                displayName: "Charlie Brown",
                description: "Community manager and content creator.",
                joinedAt: Date().addingTimeInterval(-86400 * 5), // 5 days ago
                avatar: nil,
                isActive: false
            )
        ]
        
        // Create mock invite codes
        mockInviteCodes = [
            InviteCode(
                id: "abc-123-xyz",
                uses: [],
                createdAt: Date().addingTimeInterval(-86400 * 20), // 20 days ago
                disabled: false
            ),
            InviteCode(
                id: "def-456-uvw",
                uses: [
                    CodeUse(usedBy: "did:plc:abcdef123456", usedAt: ISO8601DateFormatter().string(from: Date().addingTimeInterval(-86400 * 10)))
                ],
                createdAt: Date().addingTimeInterval(-86400 * 25), // 25 days ago
                disabled: false
            ),
            InviteCode(
                id: "ghi-789-rst",
                uses: [],
                createdAt: Date().addingTimeInterval(-86400 * 15), // 15 days ago
                disabled: true
            )
        ]
    }
    
    // Refresh invite codes with UI update
    func refreshInviteCodes() async {
        if demoMode {
            // No need to do anything in demo mode, data is already loaded
            refreshUI()
            return
        }
        
        await pdsService.fetchInviteCodes()
        refreshUI()
    }
    
    // Refresh users with UI update
    func refreshUsers() async {
        if demoMode {
            // No need to do anything in demo mode, data is already loaded
            refreshUI()
            return
        }
        
        await pdsService.fetchUsers()
        refreshUI()
    }
    
    // Disable invite code with guaranteed UI update
    func disableInviteCode(_ code: String) async -> Bool {
        if demoMode {
            // In demo mode, just update our mock data
            if let index = mockInviteCodes.firstIndex(where: { $0.id == code }) {
                mockInviteCodes[index].disabled = true
                refreshUI()
                return true
            }
            return false
        }
        
        let result = await pdsService.disableInviteCode(code)
        refreshUI()
        return result
    }
    
    // Create invite code in demo mode
    func createInviteCode() async -> InviteCode? {
        if demoMode {
            // Generate a random code in demo mode
            let randomCode = "demo-\(Int.random(in: 100...999))-\(UUID().uuidString.prefix(4))"
            let newCode = InviteCode(
                id: randomCode,
                uses: [],
                createdAt: Date(),
                disabled: false
            )
            mockInviteCodes.append(newCode)
            refreshUI()
            return newCode
        }
        
        let code = await pdsService.createInviteCode()
        await refreshInviteCodes()
        return code
    }
    
    // Suspend user in demo mode
    func suspendUser(userId: String) async -> Bool {
        if demoMode {
            print("Suspending user in demo mode: \(userId)")
            return await withCheckedContinuation { continuation in
                DispatchQueue.main.async {
                    if let user = self.mockUsers.first(where: { $0.id == userId }) {
                        print("Found user \(user.displayName), setting isActive to false")
                        user.isActive = false
                        self.refreshUI()
                        continuation.resume(returning: true)
                    } else {
                        print("User not found in mockUsers: \(userId)")
                        continuation.resume(returning: false)
                    }
                }
            }
        }
        
        let success = await pdsService.suspendUser(userId: userId, reason: "Demo suspension")
        await refreshUsers()
        return success
    }
    
    // Reactivate user in demo mode
    func reactivateUser(userId: String) async -> Bool {
        if demoMode {
            print("Reactivating user in demo mode: \(userId)")
            return await withCheckedContinuation { continuation in
                DispatchQueue.main.async {
                    if let user = self.mockUsers.first(where: { $0.id == userId }) {
                        print("Found user \(user.displayName), setting isActive to true")
                        user.isActive = true
                        self.refreshUI()
                        continuation.resume(returning: true)
                    } else {
                        print("User not found in mockUsers: \(userId)")
                        continuation.resume(returning: false)
                    }
                }
            }
        }
        
        let success = await pdsService.reactivateUser(userId: userId)
        await refreshUsers()
        return success
    }
    
    // Edit user handle in demo mode
    func editUserHandle(userId: String, newHandle: String) async -> Bool {
        if demoMode {
            if let user = mockUsers.first(where: { $0.id == userId }) {
                user.handle = newHandle
                refreshUI()
                return true
            }
            return false
        }
        
        let success = await pdsService.editUserHandle(userId: userId, newHandle: newHandle)
        await refreshUsers()
        return success
    }
    
    func login(serverURL: String, username: String, password: String) async {
        print("PDSViewModel: login called")
        if let credentials = PDSCredentials(serverURL: serverURL, username: username, password: password) {
            let success = await pdsService.login(credentials: credentials)
            print("PDSViewModel: login completed, success = \(success), isAuthenticated = \(pdsService.isAuthenticated)")
            
            // Force update the view by triggering objectWillChange
            objectWillChange.send()
        } else {
            pdsService.errorMessage = "Invalid credentials"
        }
    }
    
    func logout() {
        print("PDSViewModel: logout called")
        if demoMode {
            disableDemoMode()
        } else {
            pdsService.logout()
        }
        objectWillChange.send()
    }
}

struct AlertItem: Identifiable {
    let id = UUID()
    let title: String
    let message: String
} 