import SwiftUI

struct OnboardingView: View {
    enum InterfaceState {
        case initial
        case askForNotificationPermission
        case selectNotificationOptions
        case postcode
        case allDone
    }
    
    @EnvironmentObject var userService: UserService
    @EnvironmentObject var contentService: ContentService
    @State private var interfaceState: InterfaceState = .initial
    @State private var showExistingNotificationsAlert: Bool = false
    @State private var alertMessage: String? = nil
    
    @State private var postcode: Int = 2600
    
    private var hasLoadedTopics: Bool {
        !contentService.topics.isEmpty
    }
    
    var body: some View {
        let alertBinding = Binding<Bool> {
            alertMessage != nil
        } set: { newValue in
            if !newValue {
                alertMessage = nil
            }
        }
        
        ZStack {
            ColorName.background.color
                .ignoresSafeArea()
            
            switch interfaceState {
            case .initial:
                VStack {
                    Spacer()
                    
                    ImageName.workmarkWithByline.image
                        .padding(.bottom, 40)
                    
                    Text("Welcome to Riotact, where local voices create stronger communities.")
                        .textStyle(.title3)
                        .multilineTextAlignment(.center)
                    
                    Spacer()
                    
                    ZStack(alignment: .center) {
                        
                        ProgressView()
                            .progressViewStyle(CircularProgressViewStyle())
                            .opacity(hasLoadedTopics ? 0 : 1)
                        
                        Button {
                            withAnimation {
                                interfaceState = .askForNotificationPermission
                            }
                        } label: {
                            Text("Next")
                        }
                        .buttonStyle(PrimaryButtonStyle())
                        .opacity(hasLoadedTopics ? 1 : 0)
                        .disabled(!hasLoadedTopics)
                        
                    }
                    .transition(.opacity)
                    .animation(.easeInOut, value: hasLoadedTopics)
                }
                .padding()
                
            case .askForNotificationPermission:
                
                VStack {
                    Spacer()
                    
                    Text("Set up notifications")
                        .textStyle(.title1)
                        .multilineTextAlignment(.center)
                        .padding(.bottom, 26)
                    
                    Text("Riotact can notify you when stories about the topics you care about are published.")
                        .textStyle(.body)
                        .multilineTextAlignment(.center)
                    Spacer()
                    
                    VStack(spacing: 20) {
                        Button {
                            if userService.notificationSettings?.authorizationStatus == .authorized {
                                withAnimation {
                                    interfaceState = .selectNotificationOptions
                                }
                            } else
                            if userService.notificationSettings?.authorizationStatus == .denied {
                                showExistingNotificationsAlert = true
                            } else {
                                Task {
                                    await userService.requestNotificationPermission()
                                }
                            }
                        } label: {
                            Text("Set up notifications now")
                        }
                        .buttonStyle(PrimaryButtonStyle())
                        
                        Button {
                            withAnimation {
                                interfaceState = .postcode
                            }
                        } label: {
                            Text("I'll do it later.")
                        }
                        .buttonStyle(SecondaryButtonStyle())
                    }
                    
                }
                .padding()
                
            case .selectNotificationOptions:
                VStack {
                    Text("Select Topics")
                        .textStyle(.title1)
                        .multilineTextAlignment(.center)
                        .padding(.top, 40)
                        .padding(.bottom, 26)
                        .padding(.horizontal)
                    
                    Text("Select the topics you'd like to be notified about.")
                        .textStyle(.body)
                        .multilineTextAlignment(.center)
                        .padding(.horizontal)
                    
                    ScrollView {
                        NotificationsOptions()
                            .padding(.horizontal)
                    }
                    
                    Spacer()
                    
                    Button {
                        withAnimation {
                            interfaceState = .postcode
                        }
                    } label: {
                        Text("Next")
                    }
                    .buttonStyle(PrimaryButtonStyle())
                    .padding(.horizontal)
                }
                .padding(.vertical)
            
            case .postcode:
                VStack {
                    Spacer()
                    
                    Text("Personalising your experience")
                        .textStyle(.title1)
                        .multilineTextAlignment(.center)
                        .padding(.bottom, 26)
                    
                    Text("Riotact can prioritise the articles that impact your postcode.")
                        .textStyle(.body)
                        .multilineTextAlignment(.center)
                   
                    TextField("Your Postcode", value: $postcode, formatter: NumberFormatter.postcodeFormatter)
                        .keyboardType(.decimalPad)
                        .textStyle(.title1)
                        .multilineTextAlignment(.center)
                        .padding(.horizontal, 6)
                        .padding(.vertical, 6)
                        .background(RoundedRectangle(cornerRadius: 6).fill(ColorName.background.color(variation: .secondary)))
                        .frame(maxWidth: 400)
                    
                    Spacer()
                    
                    VStack(spacing: 20) {
                        Button {
                            guard (2600...2999).contains(postcode) else {
                                alertMessage = "Please enter a valid ACT postcode."
                                return
                            }
                            
                            userService.userPostcode = postcode
                            withAnimation {
                                interfaceState = .allDone
                            }
                        } label: {
                            Text("Add Postcode")
                        }
                        .buttonStyle(PrimaryButtonStyle())
                        
                        Button {
                            withAnimation {
                                interfaceState = .allDone
                            }
                        } label: {
                            Text("Skip this for now.")
                        }
                        .buttonStyle(SecondaryButtonStyle())
                    }
                    
                }
                .padding()
                
            case .allDone:
                VStack {
                    Spacer()
                    Text("All Done!")
                        .textStyle(.title1)
                        .multilineTextAlignment(.center)
                        .padding(.bottom, 26)
                    
                    Text("Enjoy being part of our community.")
                        .textStyle(.body)
                        .multilineTextAlignment(.center)
                    
                    Spacer()
                    
                    Button {
                        withAnimation {
                            userService.hasSeenOnboarding = true
                        }
                    } label: {
                        Text("Get Started")
                    }
                    .buttonStyle(PrimaryButtonStyle())
                }
                .padding()
            }
            
            
            
            VStack {
                ImageName.logo.image
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: logoWidth)
                    .offset(logoOffset)
                    .foregroundColor(ColorName.tint.color)
                Spacer()
            }
            
            VStack {
                ImageName.wordmark.image
                    .opacity(interfaceState == .initial ? 0 : 1)
                Spacer()
            }
        }
        .transition(.move(edge: .bottom))
        .preferredColorScheme(.dark)
        .onAppear(perform: {
            postcode = userService.userPostcode
            Task {
                await userService.updateNotificationSettings()
            }
        })
        .onChange(of: userService.notificationSettings) { notificationSettings in
            if interfaceState == .askForNotificationPermission {
                withAnimation {
                    if let authStatus = notificationSettings?.authorizationStatus, authStatus == .authorized {
                        interfaceState = .selectNotificationOptions
                    } else {
                        interfaceState = .allDone
                    }
                }
            }
        }
        .alert(isPresented: $showExistingNotificationsAlert) {
            Alert(title: Text("Enable Notifications"),
                  message: Text("Open settings to enable notifications for Riotact."),
                  dismissButton: .default(Text("Open Settings"), action: {
                UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
            }))
        }
        .alert(isPresented: alertBinding) {
            Alert(title: Text("Alert"),
                  message: Text(alertMessage ?? ""),
                  dismissButton: .default(Text("Okay"), action: {
                alertMessage = nil
            }))
        }

    }
    
    private var logoWidth: CGFloat {
        if interfaceState == .initial {
            return 300
        }
        return 22
        
    }
    
    private var logoOffset: CGSize {
        if interfaceState == .initial {
            return CGSize(width: 0, height: -150)
        }
        return CGSize(width: -21, height: 7)
        
    }
    
    
}

#if DEBUG
struct OnboardingView_Previews: PreviewProvider {
    static var previews: some View {
        OnboardingView()
            .environmentObject(UserService.preview)
    }
}
#endif
