import APIClient
import ComponentLibrary
import ComposableArchitecture
import Localization
import SwiftUI
import Utilities

// swiftlint:disable file_length

public struct CustomModeView: View {
    @Bindable var store: StoreOf<BlendedCreatePromptBuilder>
    @FocusState private var focusedField: BlendedCreatePromptBuilder.FocusedField?

    public init(store: StoreOf<BlendedCreatePromptBuilder>) {
        self.store = store
    }

    public let placeholders: [String] = [
        L10n.FeatureCreateClip.promptPlaceholder1,
        L10n.FeatureCreateClip.promptPlaceholder2,
        L10n.FeatureCreateClip.promptPlaceholder3,
    ]

    public var body: some View {
        customView
            .scrollIndicators(.hidden)
            // Leave room for controls
            .contentMargins(.bottom, 40, for: .scrollContent)
            .onTapGesture { self.dismissKeyboard() }
            .bind($store.focusedField, to: $focusedField)
    }

    private var customView: some View {
        return FadingEdgesScrollView {
            VStack(spacing: 10) {
                if let audioRecording = store.prompt.audioRecording {
                    AudioUploadDetailView(
                        audioRecording: audioRecording,
                        uploadState: store.audioUploadState,
                        imageUrl: store.imageUrl,
                        isPlaying: store.isPlaying,
                        isPlayButtonDisabled: store.isPlayButtonDisabled,
                        elapsedTime: store.elapsedTime.seconds,
                        totalTime: audioRecording.duration,
                        elapsed: store.clipDuration,
                        playPause: { store.send(.audio(.didTapTogglePlay)) },
                        delete: { store.send(.audio(.didTapDeleteClip)) },
                        selectedStyle: store.prompt.audioCreateStyle,
                        didTapCreateStyle: { store.send(.audio(.didTapCreateStyleButton)) }
                    )
                }

                LyricsSectionView(store: store)

                StylesSectionView(store: store, focusedField: $focusedField)

                AdvancedOptionsSectionView(store: store, focusedField: $focusedField)

                titleView

                // Custom mode needs a bit more of a margin
                // This is hacky but to be cleaned up later
                Color.clear
                    .frame(height: 60)
            }
        }
        .task {
            store.send(.custom(.task))
        }
    }

    private var titleView: some View {
        VStack(spacing: 0) {
            // Header
            // `.firstTextBaseline` is not working here
            HStack(spacing: 2) {
                Text(L10n.FeatureCreateClip.title)
                    .typographyV1(.subtitleMedium)
                    .foregroundStyle(Color.SemanticV2.foregroundPrimary)

                Text("(\(L10n.FeatureCreateClip.optional))")
                    .typographyV1(.body4New)
                    .baselineOffset(-2) // Align with main label.
                    .foregroundStyle(Color.SemanticV2.foregroundTertiary)

                Spacer()
            }
            .padding(.horizontal, 20)

            Color.clear
                .frame(height: 18)

            // Entry
            CharacterLimitedTextField(placeholder: L10n.FeatureCreateClip.titlePlaceholder, text: $store.prompt.title, characterLimit: store.titleCharCountLimit)
                .typographyV1(.bodyMedium)
                .accentColor(.SemanticV2.accentBrand)
                .padding(.horizontal, 15)
                .padding(.top, 15)
                .padding(.bottom, 10)
                .background {
                    RoundedRectangle(cornerRadius: 10)
                        .fill(.clear)
                        .strokeBorder(Color.SemanticV2.borderPrimary, lineWidth: 1)
                }
                .padding(.horizontal, 10)
        }
        .padding(.top, 18)
        .padding(.bottom, 10)
        .background {
            RoundedRectangle(cornerRadius: 20)
                .fill(Color.SemanticV2.backgroundSecondary)
        }
    }
}

// MARK: Lyrics Section

struct LyricsSectionView: View {
    @FocusState var focusedField: BlendedCreatePromptBuilder.FocusedField?
    @Bindable var store: StoreOf<BlendedCreatePromptBuilder>
    @State private var textHeight: CGFloat = 0
    @State private var displayHeight: CGFloat = 40 // Initial minimum height
    @State var lastLyricsMode: BlendedCreatePrompt.LyricsMode = .auto

    private var instrumentalToggleLyricsModeBinding: Binding<Bool> {
        Binding<Bool>(
            get: { store.prompt.lyricsMode == .instrumental },
            set: { newValue in
                withAnimation {
                    if newValue {
                        self.lastLyricsMode = store.prompt.lyricsMode
                        store.prompt.lyricsMode = .instrumental
                    } else if store.prompt.lyricsMode == .instrumental {
                        store.prompt.lyricsMode = self.lastLyricsMode
                    }
                }
            }
        )
    }

    init(store: StoreOf<BlendedCreatePromptBuilder>) {
        self.store = store
    }

    var body: some View {
        VStack {
            header
                .padding(.horizontal, 20)

            if store.prompt.lyricsMode != .instrumental {
                lyricsEntry
                    .padding(.horizontal, 10)

                HStack {
                    generateLyricsButton
                        .frame(height: 44)

                    Spacer()
                }
                .padding(.top, 10)
                .padding(.horizontal, 10)
            }
        }
        .bind($store.focusedField, to: $focusedField)
        .padding(.top, 18)
        .padding(.bottom, 10)
        .background {
            RoundedRectangle(cornerRadius: 20)
                .fill(Color.SemanticV2.backgroundSecondary)
        }
    }

    @ViewBuilder
    private var header: some View {
        VStack {
            HStack {
                Text(L10n.FeatureCreateClip.lyrics)
                    .typographyV1(.subtitleMedium)
                    .foregroundStyle(Color.SemanticV2.foregroundPrimary)

                Spacer()

                instrumentalToggle
            }
        }
    }

    @ViewBuilder
    private var instrumentalToggle: some View {
        HStack {
            Text(L10n.FeatureCreateClip.instrumental)
                .typographyV1(.subtitleMedium)
                .foregroundStyle(Color.SemanticV2.foregroundPrimary)

            Toggle("", isOn: instrumentalToggleLyricsModeBinding)
                .toggleStyle(.switch)
                .tint(.orange)
                .scaleEffect(0.8)
                .labelsHidden() // SwiftUI toggles automatically align to their parent's trailing edge without this
        }
    }

    @ViewBuilder
    private var lyricsEntry: some View {
        CharacterLimitedTextEditor(
            placeholder: L10n.FeatureCreateClip.blendedCreateLyricsPlaceholder,
            text: $store.prompt.lyrics,
            characterLimit: store.lyricsCharCountLimit
        )
        .focused($focusedField, equals: .custom(.lyrics))
        .typographyV1(.bodyMedium)
        .foregroundStyle(Color.SemanticV2.foregroundPrimary)
        .tint(.SemanticV2.accentBrand)
        .padding(.horizontal, 15)
        .padding(.top, 15)
        .padding(.bottom, 10)
        .frame(minHeight: 120, maxHeight: 240)
        .background {
            RoundedRectangle(cornerRadius: 10)
                .fill(.clear)
                .strokeBorder(Color.SemanticV2.borderPrimary, lineWidth: 1)
        }
    }

    @ViewBuilder
    private var generateLyricsButton: some View {
        Button {
            store.send(.custom(.didTapGenerateLyrics))
            UIImpactFeedbackGenerator(style: .medium).impactOccurred()
        } label: {
            HStack {
                if store.isGeneratingLyrics {
                    ProgressView()
                }

                Text(store.generateLyricsButtonText)
                    .typographyV1(.subtitleMedium)
                    .foregroundStyle(Color.SemanticV2.foregroundPrimary)
                    .padding(.vertical, 10)
                    .padding(.horizontal, 12)
                    .background(Color.SemanticV2.backgroundGlassThin)
                    .cornerRadius(24)
            }
        }
        .disabled(store.isGeneratingLyrics)
        .buttonStyle(.plain)
    }
}

// MARK: Styles Section

public struct StylesSectionView: View {
    @FocusState.Binding var focusedField: BlendedCreatePromptBuilder.FocusedField?
    @Bindable var store: StoreOf<BlendedCreatePromptBuilder>

    public init(store: StoreOf<BlendedCreatePromptBuilder>, focusedField: FocusState<BlendedCreatePromptBuilder.FocusedField?>.Binding) {
        self.store = store
        self._focusedField = focusedField
    }

    public var body: some View {
        VStack {
            header
                .padding(.horizontal, 20)
                .padding(.bottom, 5)

            stylesEntry
                .padding(10)
        }
        .padding(.vertical, 18)
        .background { Color.SemanticV2.backgroundSecondary }
        .clipShape(RoundedRectangle(cornerRadius: 20))
    }

    @ViewBuilder
    private var header: some View {
        HStack {
            Image.Icon.addMusic
                .foregroundStyle(Color.SemanticV1.iconPrimary)
                .frame(width: 16, height: 16)

            Text(L10n.FeatureCreateClip.styles)
                .typographyV1(.subtitleMedium)
                .foregroundStyle(Color.SemanticV1.textPrimary)

            Spacer()
        }
    }

    @ViewBuilder
    private var stylesEntry: some View {
        VStack(alignment: .leading, spacing: 8) {
            // Text entry
            CharacterLimitedTextEditor(
                placeholder: L10n.FeatureCreateClip.stylePlaceholder,
                text: $store.prompt.styleText,
                characterLimit: store.stylesCharCountLimit
            )
            .focused($focusedField, equals: .custom(.styles))
            .typographyV1(.bodyMedium)
            .foregroundStyle(Color.SemanticV2.foregroundPrimary)
            .tint(.SemanticV2.accentBrand)
            .frame(minHeight: 100)
            .clipShape(.rect)

            recommendedStylesPicker
                .padding(.top, 10)
        }
        .padding(.horizontal, 15)
        .padding(.top, 15)
        .padding(.bottom, 10)
        .background {
            RoundedRectangle(cornerRadius: 10)
                .fill(.clear)
                .strokeBorder(Color.SemanticV1.borderSecondary, lineWidth: 1)
        }
    }

    @ViewBuilder
    private var recommendedStylesPicker: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 6) {
                // Show refresh button first if we have any tags at all
                if !store.recommendedStyles.isEmpty {
                    Button {
                        store.send(.custom(.didTapRefreshRecommendedStyleTags), animation: .default)
                        UIImpactFeedbackGenerator(style: .medium).impactOccurred()
                    } label: {
                        Circle()
                            .fill(.clear)
                            .stroke(Color.SemanticV2.borderSecondary, lineWidth: 1)
                            .frame(width: 44, height: 44)
                            .overlay {
                                Image.Icon.refresh
                                    .foregroundStyle(Color.SemanticV1.iconPrimary)
                                    .frame(width: 14, height: 14)
                            }
                    }
                    .buttonStyle(ScaleButtonStyle(scaleAmount: 0.9))
                }

                // Tags
                ForEach(store.recommendedStyles, id: \.self) { style in
                    Button {
                        store.send(.custom(.didSelectStyle(style)), animation: .easeInOut)
                        UIImpactFeedbackGenerator(style: .light).impactOccurred()
                    } label: {
                        Text(style)
                            .typographyV1(.subtitleSmallNew)
                            .foregroundStyle(Color.SemanticV2.foregroundSecondary)
                            .padding(.horizontal, 12)
                            .frame(height: 44)
                            .background {
                                Capsule()
                                    .fill(.clear)
                                    .stroke(Color.SemanticV2.borderSecondary, lineWidth: 1)
                            }
                    }
                    .buttonStyle(ScaleButtonStyle(scaleAmount: 0.9))
                }
            }
        }
        .ignoresSafeArea(.container, edges: .horizontal)
        .scrollBounceBehavior(.basedOnSize)
    }

    @ViewBuilder
    private var excludeStylesEntry: some View {
        VStack(alignment: .leading, spacing: 8) {
            // Text entry
            CharacterLimitedTextField(text: $store.prompt.excludeStyleText, axis: .vertical, characterLimit: store.excludeStylesCharCountLimit)
                .textFieldStyle(BlendedTextFieldStyle(placeholders: [L10n.FeatureCreateClip.excludeStylesPlaceholder], typography: .bodyMedium))
                .focused($focusedField, equals: .custom(.excludeStyles))
                .fixedSize(horizontal: false, vertical: true)
                .lineLimit(5...)
                .clipShape(.rect)
        }
        .padding(.horizontal, 15)
        .padding(.top, 15)
        .padding(.bottom, 10)
        .background {
            RoundedRectangle(cornerRadius: 10)
                .fill(.clear)
                .strokeBorder(Color.SemanticV1.borderSecondary, lineWidth: 1)
        }
    }
}

// MARK: - Advanced Options

public struct AdvancedOptionsSectionView: View {
    @FocusState.Binding var focusedField: BlendedCreatePromptBuilder.FocusedField?
    @Bindable var store: StoreOf<BlendedCreatePromptBuilder>

    public init(store: StoreOf<BlendedCreatePromptBuilder>, focusedField: FocusState<BlendedCreatePromptBuilder.FocusedField?>.Binding) {
        self.store = store
        self._focusedField = focusedField
    }

    public var body: some View {
        VStack {
            header
                .padding(.horizontal, 20)
                .padding(.bottom, 5)

            if store.prompt.useAdvancedOptions {
                VStack(spacing: 8) {
                    // Exclude Styles
                    excludeStylesEntry

                    /// Only show sliders for paid users
                    if store.showSliders {
                        // Weirdness Slider
                        SliderRow(
                            title: L10n.FeatureCreateClip.weirdness,
                            infoPopoverText: L10n.FeatureCreateClip.weirdnessTooltip,
                            sliderValue: $store.prompt.weirdnessConstraint,
                            warningThreshold: 0.8
                        )
                        .onTapGesture(count: 2) {
                            store.send(.custom(.didDoubleTapWeirdnessSlider))
                        }

                        // Style Influence Slider
                        SliderRow(
                            title: L10n.FeatureCreateClip.styleInfluence,
                            infoPopoverText: L10n.FeatureCreateClip.styleInfluenceTooltip,
                            sliderValue: $store.prompt.styleWeight
                        )
                        .onTapGesture(count: 2) {
                            store.send(.custom(.didDoubleTapStyleWeightSlider))
                        }

                        /// Only show audio influence sliders if we have a clip
                        if store.prompt.isAudioCreate {
                            // Audio Influence Slider
                            SliderRow(
                                title: L10n.FeatureCreateClip.audioInfluence,
                                infoPopoverText: L10n.FeatureCreateClip.audioInfluenceTooltip,
                                sliderValue: $store.prompt.audioWeight
                            )
                            .onTapGesture(count: 2) {
                                store.send(.custom(.didDoubleTapAudioWeightSlider))
                            }
                        }
                    }
                }
                .padding(.horizontal, 12)
            }
        }
        .padding(.vertical, 18)
        .background { Color.SemanticV2.backgroundSecondary }
        .clipShape(RoundedRectangle(cornerRadius: 20))
    }

    @ViewBuilder
    private var header: some View {
        HStack {
            Text(L10n.FeatureCreateClip.advancedOptions)
                .typographyV1(.subtitleMedium)
                .foregroundStyle(Color.SemanticV2.foregroundPrimary)

            if store.showSliders {
                Text(L10n.FeatureCreateClip.newTag)
                    .typographyV1(.subtitleXsmall)
                    .foregroundStyle(Color.SemanticV2.foregroundPrimaryOnLight)
                    .padding(.vertical, 2)
                    .padding(.horizontal, 4)
                    .background {
                        RoundedRectangle(cornerRadius: 6)
                            .fill(Color.SemanticV2.accentBrand)
                    }
            }

            if store.prompt.slidersHaveChanges {
                Button {
                    store.send(.custom(.didTapResetSliders))
                } label: {
                    Circle()
                        .fill(Color.SemanticV2.backgroundTertiary)
                        .frame(width: 24, height: 24)
                        .overlay {
                            Image.Icon.editUndo
                                .resizable()
                                .renderingMode(.template)
                                .foregroundStyle(Color.SemanticV2.foregroundPrimary)
                                .frame(width: 10, height: 10)
                        }
                }
            }

            Spacer()

            Button {
                UIImpactFeedbackGenerator(style: .light).impactOccurred()
                store.send(.custom(.didTapAdvancedOptionsExpandButton), animation: .default)
            } label: {
                Image.Icon.chevronDown
                    .resizable()
                    .foregroundStyle(Color.SemanticV2.foregroundPrimary)
                    .rotationEffect(.degrees(store.prompt.useAdvancedOptions ? 180 : 0))
                    .frame(width: 16, height: 16)
            }
            .frame(width: 22, height: 22)
            .buttonStyle(ScaleButtonStyle(scaleAmount: 0.9))
        }
    }

    @ViewBuilder
    private var excludeStylesEntry: some View {
        HStack {
            Image.Icon.excludeMusic
                .foregroundStyle(Color.SemanticV2.foregroundPrimary)
                .frame(width: 16, height: 16)

            CharacterLimitedTextField(text: $store.prompt.excludeStyleText, characterLimit: store.excludeStylesCharCountLimit)
                .textFieldStyle(BlendedTextFieldStyle(placeholders: [L10n.FeatureCreateClip.enterStylesToExclude], typography: .subtitleSmallNew))
                .focused($focusedField, equals: .custom(.excludeStyles))
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 12)
        .background(Color.SemanticV2.backgroundPrimary)
        .cornerRadius(8)
    }
}
