//
//  V2LoginView.swift
//  Nextcloud Cookbook iOS Client
//
//  Created by Vincent Meilinger on 21.11.23.
//

import Foundation
import SwiftUI

enum V2LoginStage: LoginStage {
    case serverAddress, login, validate
    
    func next() -> V2LoginStage {
        switch self {
        case .serverAddress: return .login
        case .login: return .validate
        case .validate: return .validate
        }
    }
    
    func previous() -> V2LoginStage {
        switch self {
        case .serverAddress: return .serverAddress
        case .login: return .serverAddress
        case .validate: return .login
        }
    }
}

struct CollapsibleView<T: View>: View {
    @State var titleColor: Color = .white
    @State var content: () -> T
    @State var title: () -> Text
    
    @State var isCollapsed: Bool = true
    @State var rotationAngle: Double = -90
    
    var body: some View {
        VStack(alignment: .leading) {
            Button {
                withAnimation(.easeInOut(duration: 0.2)) {
                    isCollapsed.toggle()
                    if isCollapsed {
                        rotationAngle += 90
                    } else {
                        rotationAngle -= 90
                    }
                }
                rotationAngle = isCollapsed ? -90 : 0
            } label: {
                HStack {
                    Image(systemName: "chevron.down")
                        .bold()
                        .rotationEffect(Angle(degrees: rotationAngle))
                    title()
                }.foregroundStyle(titleColor)
            }
            
            if !isCollapsed {
                content()
                    .padding(.top, 1)
            }
        }
    }
}

struct V2LoginView: View {
    @Binding var showAlert: Bool
    @Binding var alertMessage: String
    
    @State var loginStage: V2LoginStage = .serverAddress
    @State var loginRequest: LoginV2Request? = nil
    @FocusState private var focusedField: Field?
    
    @AppStorage("serverAddress") var serverAddress = ""
    @AppStorage("username") var userName = ""
    @AppStorage("token") var token = ""
    @AppStorage("onboarding") var onboarding = true
    
    // TextField handling
    enum Field {
        case server
        case username
        case token
    }
    
    var body: some View {
        ScrollView {
            VStack(alignment: .leading) {
                LoginLabel(text: "Server address")
                    .padding()
                LoginTextField(example: "e.g.: example.com", text: $serverAddress, color: loginStage == .serverAddress ? .white : .secondary)
                    .focused($focusedField, equals: .server)
                    .textContentType(.URL)
                    .submitLabel(.done)
                    .padding([.bottom, .horizontal])
                    .onSubmit {
                        withAnimation(.easeInOut) {
                            loginStage = loginStage.next()
                        }
                    }
                
                CollapsibleView {
                    VStack(alignment: .leading) {
                        Text("Make sure to enter the server address in the form 'example.com'. Currently, only servers using the 'https' protocol are supported.")
                        if let loginRequest = loginRequest {
                            Text("If the login button does not open your browser, copy the following link and paste it in your browser manually:")
                            Text(loginRequest.login)
                        }
                    }
                } title: {
                    Text("Show help")
                        .foregroundColor(.white)
                        .font(.headline)
                }.padding()
                
                if loginStage == .login || loginStage == .validate {
                    Text("The 'Login' button will open a web browser. Please follow the login instructions provided there.\nAfter a successful login, return to this application and press 'Validate'.")
                        .font(.subheadline)
                        .foregroundStyle(.white)
                        .padding()
                }
                HStack {
                    if loginStage == .login || loginStage == .validate {
                        Button {
                            if serverAddress == "" {
                                alertMessage = "Please enter a valid server address."
                                showAlert = true
                                return
                            }
                            
                            Task {
                                await sendLoginV2Request()
                                if let loginRequest = loginRequest {
                                    await UIApplication.shared.open(URL(string: loginRequest.login)!)
                                } else {
                                    alertMessage = "Unable to reach server. Please check your server address and internet connection."
                                    showAlert = true
                                }
                            }
                            loginStage = loginStage.next()
                        } label: {
                            Text("Login")
                                .foregroundColor(.white)
                                .font(.headline)
                                .padding()
                                .background(
                                    RoundedRectangle(cornerRadius: 10)
                                        .stroke(Color.white, lineWidth: 2)
                                        .foregroundColor(.clear)
                                )
                        }.padding()
                    }
                    if loginStage == .validate {
                        Spacer()
                        
                        Button {
                            // fetch login v2 response
                            Task {
                                guard let res = await fetchLoginV2Response() else {
                                    alertMessage = "Login failed. Please login via the browser and try again."
                                    showAlert = true
                                    return
                                }
                                print("Login successfull for user \(res.loginName)!")
                                self.userName = res.loginName
                                self.token = res.appPassword
                                self.onboarding = false
                            }
                        } label: {
                            Text("Validate")
                                .foregroundColor(.white)
                                .font(.headline)
                                .padding()
                                .background(
                                    RoundedRectangle(cornerRadius: 10)
                                        .stroke(Color.white, lineWidth: 2)
                                        .foregroundColor(.clear)
                                )
                        }
                        .disabled(loginRequest == nil ? true : false)
                        .padding()
                    }
                }
            }
        }
    }
    
    func sendLoginV2Request() async {
        let hostPath = "https://\(serverAddress)"
        let headerFields: [HeaderField] = [
            //HeaderField.ocsRequest(value: true),
            //HeaderField.accept(value: .JSON)
        ]
        let request = RequestWrapper.customRequest(
            method: .POST,
            path: .LOGINV2REQ,
            headerFields: headerFields
        )
        do {
            let (data, _): (Data?, Error?) = try await NetworkHandler.sendHTTPRequest(
                request,
                hostPath: hostPath,
                authString: nil
            )
            
            guard let data = data else { return }
            print("Data: \(data)")
            let loginReq: LoginV2Request? = JSONDecoder.safeDecode(data)
            self.loginRequest = loginReq
        } catch {
            print("Could not establish communication with the server.")
        }
        
    }
    
    func fetchLoginV2Response() async -> LoginV2Response? {
        guard let loginRequest = loginRequest else { return nil }
        let headerFields = [
            HeaderField.ocsRequest(value: true),
            HeaderField.accept(value: .JSON),
            HeaderField.contentType(value: .FORM)
        ]
        let request = RequestWrapper.customRequest(
            method: .POST,
            path: .NONE,
            headerFields: headerFields,
            body: "token=\(loginRequest.poll.token)".data(using: .utf8),
            authenticate: false
        )
        
        var (data, error): (Data?, Error?) = (nil, nil)
        do {
            (data, error) = try await NetworkHandler.sendHTTPRequest(
                request,
                hostPath: loginRequest.poll.endpoint,
                authString: nil
            )
        } catch {
            print("Error: ", error)
        }
        guard let data = data else { return nil }
        if let loginRes: LoginV2Response = JSONDecoder.safeDecode(data) {
            return loginRes
        }
        print("Could not decode.")
        return nil
    }
}
