//
//  Theme+Views.swift
//  Passepartout
//
//  Created by Davide De Rosa on 11/1/24.
//  Copyright (c) 2024 Davide De Rosa. All rights reserved.
//
//  https://github.com/passepartoutvpn
//
//  This file is part of Passepartout.
//
//  Passepartout is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  Passepartout is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with Passepartout.  If not, see <http://www.gnu.org/licenses/>.
//

import CommonUtils
import SwiftUI

// MARK: Shortcuts

#if !os(tvOS)
extension Theme {
    public func listSection<ItemView: View, T: EditableValue>(
        _ title: String,
        addTitle: String,
        originalItems: Binding<[T]>,
        emptyValue: (() async -> T)? = nil,
        @ViewBuilder itemLabel: @escaping (Bool, Binding<T>) -> ItemView
    ) -> some View {
        EditableListSection(
            title,
            addTitle: addTitle,
            originalItems: originalItems,
            emptyValue: emptyValue,
            itemLabel: itemLabel,
            removeLabel: ThemeEditableListSection.RemoveLabel.init(action:),
            editLabel: ThemeEditableListSection.EditLabel.init
        )
    }
}
#endif

// MARK: - Views

public struct ThemeImage: View {

    @EnvironmentObject
    private var theme: Theme

    private let name: Theme.ImageName

    public init(_ name: Theme.ImageName) {
        self.name = name
    }

    public var body: some View {
        Image(systemName: theme.systemImageName(name))
    }
}

public struct ThemeImageLabel: View {

    @EnvironmentObject
    private var theme: Theme

    private let title: String

    private let name: Theme.ImageName

    public init(_ title: String, _ name: Theme.ImageName) {
        self.title = title
        self.name = name
    }

    public var body: some View {
        Label {
            Text(title)
        } icon: {
            ThemeImage(name)
        }
    }
}

public struct ThemeCloseLabel: View {
    public init() {
    }

    public var body: some View {
#if os(iOS) || os(tvOS)
        ThemeImage(.close)
#else
        Text(Strings.Global.Actions.cancel)
#endif
    }
}

public struct ThemeCountryText: View {
    private let code: String

    private let title: String?

    public init(_ code: String, title: String? = nil) {
        self.code = code
        self.title = title ?? code.localizedAsRegionCode
    }

    public var body: some View {
        Text(
            [code.asCountryCodeEmoji, title]
                .compactMap { $0 }
                .joined(separator: " ")
        )
    }
}

public struct ThemeCountryFlag: View {
    private let code: String?

    private let placeholderTip: String?

    private let countryTip: ((String) -> String?)?

    public init(_ code: String?, placeholderTip: String? = nil, countryTip: ((String) -> String?)? = nil) {
        self.code = code
        self.placeholderTip = placeholderTip
        self.countryTip = countryTip
    }

    public var body: some View {
        if let code {
            text(withString: code.asCountryCodeEmoji, tip: countryTip?(code))
        } else {
            text(withString: "🌐", tip: placeholderTip)
        }
    }

    @ViewBuilder
    private func text(withString string: String, tip: String?) -> some View {
        if let tip {
            Text(verbatim: string)
                .help(tip)
        } else {
            Text(verbatim: string)
        }
    }
}

public struct ThemeTextField: View {
    let title: String?

    @Binding
    var text: String

    let placeholder: String

    public init(_ title: String, text: Binding<String>, placeholder: String) {
        self.title = title
        _text = text
        self.placeholder = placeholder
    }

    @ViewBuilder
    var labeledView: some View {
        if let title {
            LabeledContent {
                fieldView
            } label: {
                Text(title)
            }
        } else {
            fieldView
        }
    }

    var fieldView: some View {
        TextField(title ?? "", text: $text, prompt: Text(placeholder))
    }
}

public struct ThemeSecureField: View {
    let title: String?

    @Binding
    var text: String

    let placeholder: String

    public init(title: String?, text: Binding<String>, placeholder: String) {
        self.title = title
        _text = text
        self.placeholder = placeholder
    }

    @ViewBuilder
    var labeledView: some View {
        if let title {
            LabeledContent {
                fieldView
            } label: {
                Text(title)
            }
        } else {
            fieldView
        }
    }

    var fieldView: some View {
        RevealingSecureField(title ?? "", text: $text, prompt: Text(placeholder), imageWidth: 30.0) {
           ThemeImage(.hide)
                .foregroundStyle(Color.accentColor)
       } revealImage: {
           ThemeImage(.show)
               .foregroundStyle(Color.accentColor)
       }
    }
}

public struct ThemeProgressView: View {
    public init() {
    }

    public var body: some View {
        ProgressView()
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .id(UUID())
    }
}

#if !os(tvOS)

public struct ThemeMenuImage: View {

    @EnvironmentObject
    private var theme: Theme

    private let name: Theme.MenuImageName

    public init(_ name: Theme.MenuImageName) {
        self.name = name
    }

    public var body: some View {
        Image(theme.menuImageName(name))
    }
}

public struct ThemeDisclosableMenu<Content, Label>: View where Content: View, Label: View {

    @ViewBuilder
    private let content: () -> Content

    @ViewBuilder
    private let label: () -> Label

    public init(content: @escaping () -> Content, label: @escaping () -> Label) {
        self.content = content
        self.label = label
    }

    public var body: some View {
        Menu(content: content) {
            HStack(alignment: .firstTextBaseline) {
                label()
                ThemeImage(.disclose)
            }
            .contentShape(.rect)
        }
        .foregroundStyle(.primary)
#if os(macOS)
        .buttonStyle(.plain)
#endif
    }
}

public struct ThemeCopiableText<Value, ValueView>: View where Value: CustomStringConvertible, ValueView: View {

    @EnvironmentObject
    private var theme: Theme

    private let title: String?

    private let value: Value

    private let isMultiLine: Bool

    private let valueView: (Value) -> ValueView

    public init(
        title: String? = nil,
        value: Value,
        isMultiLine: Bool = true,
        valueView: @escaping (Value) -> ValueView
    ) {
        self.title = title
        self.value = value
        self.isMultiLine = isMultiLine
        self.valueView = valueView
    }

    public var body: some View {
        HStack {
            if let title {
                Text(title)
                Spacer()
            }
            valueView(value)
                .foregroundStyle(title == nil ? theme.titleColor : theme.valueColor)
                .themeMultiLine(isMultiLine)
            if title == nil {
                Spacer()
            }
            Button {
                Utils.copyToPasteboard(value.description)
            } label: {
                ThemeImage(.copy)
            }
            // TODO: #584, necessary to avoid cell selection
            .buttonStyle(.borderless)
        }
    }
}

public struct ThemeTappableText: View {
    private let title: String

    private let action: () -> Void

    public init(title: String, action: @escaping () -> Void) {
        self.title = title
        self.action = action
    }

    var commonView: some View {
        Button(action: action) {
            Text(title)
                .themeTruncating()
        }
    }
}

public struct ThemeRemovableItemRow<ItemView>: View where ItemView: View {
    private let isEditing: Bool

    @ViewBuilder
    private let itemView: () -> ItemView

    let removeAction: () -> Void

    public init(
        isEditing: Bool,
        @ViewBuilder itemView: @escaping () -> ItemView,
        removeAction: @escaping () -> Void
    ) {
        self.isEditing = isEditing
        self.itemView = itemView
        self.removeAction = removeAction
    }

    public var body: some View {
        RemovableItemRow(
            isEditing: isEditing,
            itemView: itemView,
            removeView: removeView
        )
    }
}

public enum ThemeEditableListSection {
    public struct RemoveLabel: View {
        let action: () -> Void

        public init(action: @escaping () -> Void) {
            self.action = action
        }
    }

    public struct EditLabel: View {
    }
}

#endif