//
//  UserProfile.swift
//  SimpleX
//
//  Created by Evgeny Poberezkin on 31/01/2022.
//  Copyright © 2022 SimpleX Chat. All rights reserved.
//

import SwiftUI
import SimpleXChat

struct UserProfile: View {
    @EnvironmentObject var chatModel: ChatModel
    @State private var profile = Profile(displayName: "", fullName: "")
    @State private var editProfile = false
    @State private var showChooseSource = false
    @State private var showImagePicker = false
    @State private var showTakePhoto = false
    @State private var chosenImage: UIImage? = nil
    @State private var alert: UserProfileAlert?
    @FocusState private var focusDisplayName

    var body: some View {
        let user: User = chatModel.currentUser!

        return VStack(alignment: .leading) {
            Text("Your profile is stored on your device and shared only with your contacts.\nSimpleX servers cannot see your profile.")
                .padding(.bottom)

            if editProfile {
                ZStack(alignment: .center) {
                    ZStack(alignment: .topTrailing) {
                        profileImageView(profile.image)
                        if user.image != nil {
                            Button {
                                profile.image = nil
                            } label: {
                                Image(systemName: "multiply")
                                    .resizable()
                                    .aspectRatio(contentMode: .fit)
                                    .frame(width: 12)
                            }
                        }
                    }

                    editImageButton { showChooseSource = true }
                }
                .frame(maxWidth: .infinity, alignment: .center)

                VStack(alignment: .leading) {
                    ZStack(alignment: .leading) {
                        if !validNewProfileName(user) {
                            Button {
                                alert = .invalidNameError(validName: mkValidName(profile.displayName))
                            } label: {
                                Image(systemName: "exclamationmark.circle").foregroundColor(.red)
                            }
                        } else {
                            Image(systemName: "exclamationmark.circle").foregroundColor(.clear)
                        }
                        profileNameTextEdit("Profile name", $profile.displayName)
                            .focused($focusDisplayName)
                    }
                    .padding(.bottom)
                    if showFullName(user) {
                        profileNameTextEdit("Full name (optional)", $profile.fullName)
                            .padding(.bottom)
                    }
                    HStack(spacing: 20) {
                        Button("Cancel") { editProfile = false }
                        Button("Save (and notify contacts)") { saveProfile() }
                            .disabled(!canSaveProfile(user))
                    }
                }
                .frame(maxWidth: .infinity, minHeight: 120, alignment: .leading)
            } else {
                ZStack(alignment: .center) {
                    profileImageView(user.image)
                        .onTapGesture { startEditingImage(user) }

                    if user.image == nil {
                        editImageButton { startEditingImage(user) }
                    }
                }
                .frame(maxWidth: .infinity, alignment: .center)

                VStack(alignment: .leading) {
                    profileNameView("Profile name:", user.profile.displayName)
                    if showFullName(user) {
                        profileNameView("Full name:", user.profile.fullName)
                    }
                    Button("Edit") {
                        profile = fromLocalProfile(user.profile)
                        editProfile = true
                        focusDisplayName = true
                    }
                }
                .frame(maxWidth: .infinity, minHeight: 120, alignment: .leading)
            }
        }
        .padding()
        .frame(maxHeight: .infinity, alignment: .top)
        .confirmationDialog("Profile image", isPresented: $showChooseSource, titleVisibility: .visible) {
            Button("Take picture") {
                showTakePhoto = true
            }
            Button("Choose from library") {
                showImagePicker = true
            }
            if UIPasteboard.general.hasImages {
                Button("Paste image") {
                    chosenImage = UIPasteboard.general.image
                }
            }
        }
        .fullScreenCover(isPresented: $showTakePhoto) {
            ZStack {
                Color.black.edgesIgnoringSafeArea(.all)
                CameraImagePicker(image: $chosenImage)
            }
        }
        .sheet(isPresented: $showImagePicker) {
            LibraryImagePicker(image: $chosenImage) { _ in
                await MainActor.run {
                    showImagePicker = false
                }
            }
        }
        .onChange(of: chosenImage) { image in
            if let image = image {
                profile.image = resizeImageToStrSize(cropToSquare(image), maxDataSize: 12500)
            } else {
                profile.image = nil
            }
        }
        .alert(item: $alert) { a in userProfileAlert(a, $profile.displayName) }
    }

    func profileNameTextEdit(_ label: LocalizedStringKey, _ name: Binding<String>) -> some View {
        TextField(label, text: name)
            .padding(.leading, 32)
    }

    func profileNameView(_ label: LocalizedStringKey, _ name: String) -> some View {
        HStack {
            Text(label)
            Text(name).fontWeight(.bold)
        }
        .padding(.bottom)
    }

    func startEditingImage(_ user: User) {
        profile = fromLocalProfile(user.profile)
        editProfile = true
        showChooseSource = true
    }

    private func validNewProfileName(_ user: User) -> Bool {
        profile.displayName == user.profile.displayName || validDisplayName(profile.displayName.trimmingCharacters(in: .whitespaces))
    }

    private func showFullName(_ user: User) -> Bool {
        user.profile.fullName != "" && user.profile.fullName != user.profile.displayName
    }

    private func canSaveProfile(_ user: User) -> Bool {
        profile.displayName.trimmingCharacters(in: .whitespaces) != "" && validNewProfileName(user)
    }

    func saveProfile() {
        Task {
            do {
                profile.displayName = profile.displayName.trimmingCharacters(in: .whitespaces)
                if let (newProfile, _) = try await apiUpdateProfile(profile: profile) {
                    DispatchQueue.main.async {
                        chatModel.updateCurrentUser(newProfile)
                        profile = newProfile
                    }
                    editProfile = false
                } else {
                    alert = .duplicateUserError
                }
            } catch {
                logger.error("UserProfile apiUpdateProfile error: \(responseError(error))")
            }
        }
    }
}

func profileImageView(_ imageStr: String?) -> some View {
    ProfileImage(imageStr: imageStr, size: 192)
}

func editImageButton(action: @escaping () -> Void) -> some View {
    Button {
        action()
    } label: {
        Image(systemName: "camera")
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 48)
    }
}

struct UserProfile_Previews: PreviewProvider {
    static var previews: some View {
        let chatModel1 = ChatModel()
        chatModel1.currentUser = User.sampleData
        let chatModel2 = ChatModel()
        chatModel2.currentUser = User.sampleData
        chatModel2.currentUser?.profile.image = "data:image/jpg;base64,[encoded data, 10212 characters]"
        return Group {
            UserProfile()
                .environmentObject(chatModel1)
            UserProfile()
                .environmentObject(chatModel2)
        }
    }
}
