import APIClient
import ClipLineageClient
import ComponentLibrary
import ComposableArchitecture
import EventBusClient
import Localization
import NavigationRouterClient
import StatsigClient
import SwiftUI
import Utilities

// swiftlint:disable file_length

@Reducer
public struct RemixActions {
    @Reducer(state: .equatable)
    public enum Destination {
        case moreInfo(MoreInfo)
    }

    @ObservableState
    public struct State: Equatable {
        @Presents public var destination: Destination.State?
        @Shared var me: Me
        let clip: Clip
        let hook: Hook?

        @Shared(.fileStorage(.savedPrompts)) var savedPrompts: [Clip.ID: Prompt] = [:]

        var directChildrenCount: Int {
            @Shared(.inMemory(.clipDirectChildrenCount)) var clipDirectChildrenCount: [ClipID: Int] = [:]
            return clipDirectChildrenCount[clip.id] ?? 0
        }

        var showSeeRemixesButton: Bool {
            directChildrenCount > 0
        }

        public init(me: Shared<Me>, clip: Clip, hook: Hook? = nil) {
            self._me = me
            self.clip = clip
            self.hook = hook
        }
    }

    public enum Action {
        case onAppear
        case dismiss
        case seeRemixesTapped
        case coverTapped
        case extendTapped
        case moreInfoTapped
        case reusePromptTapped

        case destination(PresentationAction<Destination.Action>)
    }

    public init() {}

    @Dependency(\.dismiss) var dismiss
    @Dependency(NavigationRouterClient.self) var navigationRouter
    @Dependency(\.eventBus.getCreateChannel) var getCreateChannel
    @Dependency(\.eventBus.sendHookEvent) private var sendHookEvent
    @Dependency(\.clipLineageClient) private var clipLineageClient

    public var body: some ReducerOf<Self> {
        Reduce<State, Action> { state, action in
            /// Taken from `SongActionsMenu`
            func reusablePrompt() -> Prompt {
                if var prompt = state.savedPrompts[state.clip.id] {
                    prompt.lyrics = state.clip.prompt
                    prompt.styles = state.clip.tags
                    return prompt
                } else {
                    // Audio not supported without a saved prompt
                    let generationType: GenerationType = .text
                    return Prompt(
                        title: state.clip.title,
                        lyrics: state.clip.prompt,
                        styles: state.clip.tags,
                        text: state.clip.gptDescriptionPrompt,
                        generationType: generationType
                    )
                }
            }

            switch action {
            case .onAppear:
                clipLineageClient.hydrateRelationshipsForClip(state.clip.id)
                return .none

            case .dismiss:
                return .run { _ in await self.dismiss() }

            case .seeRemixesTapped:
                // Check if we need to pause any Hooks if we're coming from a Hooks feed
                if state.hook != nil {
                    sendHookEvent(.pauseCurrentHook(cause: .navigation(.cover)))
                }
                navigationRouter.send(route: .remixesList(parentClip: state.clip))
                return .send(.dismiss)

            case .coverTapped:
                // Check if we need to pause any Hooks if we're coming from a Hooks feed
                if state.hook != nil {
                    sendHookEvent(.pauseCurrentHook(cause: .navigation(.cover)))
                }
                let prompt = reusablePrompt()
                getCreateChannel().queue(.coverClip(state.clip, prompt: prompt, hook: state.hook))
                return .send(.dismiss)

            case .extendTapped:
                // Check if we need to pause any Hooks if we're coming from a Hooks feed
                if state.hook != nil {
                    sendHookEvent(.pauseCurrentHook(cause: .navigation(.extend)))
                }
                let prompt = reusablePrompt()
                getCreateChannel().queue(.extendClip(state.clip, prompt: prompt, hook: state.hook))
                return .send(.dismiss)

            case .moreInfoTapped:
                state.destination = .moreInfo(.init(clip: state.clip, me: state.$me))
                return .none

            case .reusePromptTapped:
                let prompt = reusablePrompt()
                getCreateChannel().queue(.reusePrompt(prompt: prompt))
                return .send(.dismiss)

            case .destination:
                return .none
            }
        }
        .ifLet(\.$destination, action: \.destination)
    }
}

public struct RemixActionsSheet: View {
    let store: StoreOf<RemixActions>

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

    public var body: some View {
        VStack(spacing: 0) {
            songCard

            title
                .padding(.vertical, 16)

            if store.directChildrenCount > 0 {
                seeRemixesRow

                Divider()
            }

            /// Covers are gated
            if FeatureFlag.create.remixCover {
                coverRow

                Divider()
            }

            extendRow

            Divider()

            reusePromptRow
        }
        .sheetNavigationBar(
            leading: { EmptyView() },
            center: {
                HStack {
                    Image.Icon.remix
                        .resizable()
                        .frame(width: 20, height: 20)
                        .foregroundStyle(Color.SemanticV2.foregroundPrimary)

                    Text(L10n.FeatureClipDetail.remix)
                        .typographyV1(.subtitleLarge)
                        .foregroundStyle(Color.SemanticV2.foregroundPrimary)
                }
            },
            trailing: {
                ToolbarButton(
                    .close,
                    color: Color.SemanticV2.foregroundPrimary,
                    background: Color.SemanticV1.backgroundQuaternary
                ) {
                    store.send(.dismiss)
                }
            }
        )
        .presentationCornerRadius(40, conditional: true)
        .presentationBackground(Color.SemanticV1.backgroundPrimary) // Sheet background color consistency w/ the rest of Omniplayer
        .selfSizingPresentation()
    }

    let songCardSize = CGSize(width: 89, height: 117)
    let songCardCornerRadius: CGFloat = 8

    private var songCard: some View {
        RemoteImage(url: store.clip.largeImageUrl, fallbackId: store.clip.id.remoteId)
            .aspectRatio(contentMode: .fill)
            .frame(width: songCardSize.width, height: songCardSize.height)
            .clipShape(RoundedRectangle(cornerRadius: songCardCornerRadius))
    }

    private var title: some View {
        Text(store.clip.title)
            .typographyV1(.headline3.editorialNewLight())
            .multilineTextAlignment(.center)
            .foregroundStyle(Color.SemanticV1.textPrimary)
    }

    @ViewBuilder
    private var seeRemixesRow: some View {
        MenuRowV1(title: L10n.FeatureClipDetail.seeRemixes) {
            Image.Icon.remix
        } action: {
            store.send(.seeRemixesTapped)
        }
        .padding(.horizontal, 20)
    }

    @ViewBuilder
    private var coverRow: some View {
        MenuRowV1(title: L10n.FeatureClipDetail.cover) {
            Image.Icon.cover
        } action: {
            store.send(.coverTapped)
        }
        .padding(.horizontal, 20)
    }

    @ViewBuilder
    private var extendRow: some View {
        MenuRowV1(title: L10n.FeatureClipDetail.extend) {
            Image.Icon.extend
        } action: {
            store.send(.extendTapped)
        }
        .padding(.horizontal, 20)
    }

    @ViewBuilder
    private var reusePromptRow: some View {
        let reuseString = L10n.FeatureClipDetail.reuseStyle
        MenuRowV1(title: reuseString) {
            Image.Icon.reuse
        } action: {
            store.send(.reusePromptTapped)
        }
        .padding(.horizontal, 20)
    }
}

public struct RemixActionsSheetRedesign: View {
    @Bindable var store: StoreOf<RemixActions>
    let coverSize: CGSize = .init(width: 60, height: 80)

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

    public var body: some View {
        VStack(spacing: 8) {
            Text(L10n.FeatureClipDetail.remix)
                .typographyV1(.subtitleMedium)
                .foregroundStyle(Color.SemanticV1.textPrimary)
                .padding(.top, 16)

            VStack(spacing: 8) {
                header
                /*

                             songCard

                             title
                                 .padding(.vertical, 16)

                 //            if store.directChildrenCount > 0 {
                 //                seeRemixesRow
                 //
                 //                Divider()
                 //            }
                             */
                VStack(spacing: 0) {
                    /// Covers are gated

                    extendRow

                    Divider()
                        .overlay(Color.SemanticV1.backgroundSecondary)
                        .frame(height: 0.5)
                        .padding(.vertical, 0.05)

                    if FeatureFlag.create.remixCover {
                        coverRow

                        Divider()
                            .overlay(Color.SemanticV1.backgroundSecondary)
                            .frame(height: 0.5)
                            .padding(.vertical, 0.05)
                    }

                    reusePromptRow
                }.clipShape(RoundedRectangle(cornerRadius: 12))

                VStack(spacing: 0) {
                    if store.directChildrenCount > 0 {
                        seeRemixesRow
                    }
                }
                .clipShape(RoundedRectangle(cornerRadius: 12))

            }.padding(.horizontal, 12)
        }
        .presentationCornerRadius(40, conditional: true)
        .presentationBackground(Color.SemanticV1.backgroundPrimary) // Sheet background color consistency w/ the rest of Omniplayer
        .presentationDragIndicator(.visible)
        .selfSizingPresentation()
        .sheet(item: $store.scope(state: \.destination?.moreInfo, action: \.destination.moreInfo)) { store in
            MoreInfoView(store: store)
        }
    }

    let songCardSize = CGSize(width: 89, height: 117)
    let songCardCornerRadius: CGFloat = 8

    private var songCard: some View {
        RemoteImage(url: store.clip.largeImageUrl, fallbackId: store.clip.id.remoteId)
            .aspectRatio(contentMode: .fill)
            .frame(width: songCardSize.width, height: songCardSize.height)
            .clipShape(RoundedRectangle(cornerRadius: songCardCornerRadius))
    }

    private var title: some View {
        Text(store.clip.title)
            .typographyV1(.headline3.editorialNewLight())
            .multilineTextAlignment(.center)
            .foregroundStyle(Color.SemanticV1.textPrimary)
    }

    @ViewBuilder
    private var seeRemixesRow: some View {
        MenuRowFullWidth(title: "\(L10n.FeatureClipDetail.view) \(self.store.directChildrenCount) " + ((self.store.directChildrenCount > 1) ? L10n.FeatureClipDetail.remixes : L10n.FeatureClipDetail.remix)) {
            store.send(.seeRemixesTapped)
        } leadingView: {
            Image.Icon.playlist
                .renderingMode(.template)
                .foregroundStyle(Color.SemanticV1.iconPrimary)
        } trailingView: {
            AnyView(
                Image.Icon.caretRight
                    .renderingMode(.template)
                    .foregroundStyle(Color.SemanticV1.iconPrimary)
            )
        }
    }

    @ViewBuilder
    private var coverRow: some View {
        MenuRowFullWidth(title: "\(L10n.FeatureClipDetail.remix): \(L10n.FeatureClipDetail.cover)") {
            store.send(.coverTapped)
        } leadingView: {
            Image.Icon.coverCreate
                .renderingMode(.template)
        }
    }

    @ViewBuilder
    private var extendRow: some View {
        MenuRowFullWidth(title: "\(L10n.FeatureClipDetail.remix): \(L10n.FeatureClipDetail.extend)") {
            store.send(.extendTapped)
        } leadingView: {
            Image.Icon.extend
        }
    }

    @ViewBuilder
    private var reusePromptRow: some View {
        let reuseString = L10n.FeatureClipDetail.reuseStyle
        MenuRowFullWidth(title: "\(L10n.FeatureClipDetail.remix): \(reuseString)") {
            store.send(.reusePromptTapped)
        } leadingView: {
            Image.Icon.reuse
        }
    }

    @ViewBuilder
    private var header: some View {
        HStack(spacing: 0) {
            HStack(spacing: 12) {
                coverImage

                VStack(alignment: .leading) {
                    Text(store.clip.title)
                        .lineLimit(1)
                        .foregroundStyle(Color.SemanticV1.textPrimary)
                        .typographyV1(.heading4)

                    Text("\(L10n.FeatureClipDetail.by(store.clip.displayName))")
                        .lineLimit(1)
                        .foregroundStyle(Color.SemanticV2.foregroundInactive)
                        .typographyV1(.caption)
                }
            }
            Spacer()

            Button(action: {
                store.send(.moreInfoTapped)
            }, label: {
                Text(L10n.FeatureClipDetail.moreInfo)
                    .typographyV1(.monospaceSmall)
                    .foregroundStyle(Color.SemanticV2.foregroundInactive)
                    .padding(.vertical, 6)
                    .padding(.horizontal, 10)
            })
            .clipShape(RoundedRectangle(cornerRadius: 30))
            .overlay(
                RoundedRectangle(cornerRadius: 30)
                    .stroke(Color.SemanticV2.foregroundInactive, lineWidth: 1)
            )
        }
        .padding(.horizontal, 8)
    }

    private var coverImage: some View {
        RemoteImage(url: store.clip.largeImageUrl, fallbackId: store.clip.id.remoteId)
            .frame(width: coverSize.width, height: coverSize.height)
            .clipShape(RoundedRectangle(cornerRadius: 14))
    }
}

public struct RemixActionsSheetV2: View {
    @Bindable var store: StoreOf<RemixActions>

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

    public var body: some View {
        VStack(spacing: 0) {
            // Grabber
            grabber

            // Content
            VStack(spacing: 16) {
                // Header with artwork and title
                VStack(spacing: 16) {
                    // Artwork
                    videoAndImageCover

                    // Title and remixes button
                    VStack(spacing: 8) {
                        Text(L10n.FeatureClipDetail.remixTitle(store.clip.title))
                            .figmaMCPTypography(TypographyV1.FigmaMCP.largeTitle)
                            .foregroundStyle(Color.FigmaMCP.Semantic.foregroundPrimary)
                            .multilineTextAlignment(.center)
                            .tracking(0.36)

                        if store.showSeeRemixesButton {
                            seeRemixesButton
                        }
                    }
                }

                // Options List
                menu
            }
            .padding(.horizontal, 16)
        }
        .presentationDragIndicator(.hidden)
        .modify {
            /// Use default styling on iOS 26+
            if #available(iOS 26.0, *) {
                $0
            } else {
                $0.presentationBackground {
                    Color.FigmaMCP.Semantic.smokeDense
                        .background(.ultraThinMaterial)
                }
            }
        }
        .preferredColorScheme(.dark)
        .selfSizingPresentation()
        .onAppear { store.send(.onAppear) }
    }

    @ViewBuilder
    private var videoAndImageCover: some View {
        if let videoCoverUrl = store.clip.videoCoverUrl,
           let playableUrl = URL(string: videoCoverUrl)
        {
            ZStack {
                RemoteImage(
                    url: store.clip.largeImageUrl,
                    fallbackId: store.clip.id.remoteId
                )
                .aspectRatio(contentMode: .fill)

                LoopingVideoPlayer(
                    playableUrl: playableUrl,
                    restartBeforePlaying: false,
                    autoPlay: true,
                    isPlaying: .constant(true),
                    overrideTime: nil,
                    fallbackView: {
                        coverImage
                    }
                )
            }
            .id(store.clip.id.remoteId)
            .frame(width: 80, height: 100)
            .clipShape(RoundedRectangle(cornerRadius: 16))
        } else {
            coverImage
        }
    }

    private var coverImage: some View {
        RemoteImage(
            url: store.clip.largeImageUrl, fallbackId: store.clip.id.remoteId
        )
        .aspectRatio(contentMode: .fill)
        .frame(width: 80, height: 100)
        .clipShape(RoundedRectangle(cornerRadius: 16))
    }

    private var grabber: some View {
        VStack {
            // Drag handle - 32px wide, 4px tall, rounded
            RoundedRectangle(cornerRadius: 100)
                .fill(Color.FigmaMCP.Semantic.fogDense)
                .frame(width: 32, height: 4)
        }
        .padding(16) // 16px padding on all sides
    }

    private var seeRemixesButton: some View {
        Button {
            store.send(.seeRemixesTapped)
        } label: {
            HStack(spacing: 4) {
                Text(L10n.FeatureClipDetail.seeRemixesCount(store.directChildrenCount))
                    .figmaMCPTypography(TypographyV1.FigmaMCP.xSmallTitle)
                    .foregroundStyle(Color.FigmaMCP.Semantic.foregroundPrimary)
                    .tracking(0.24)

                Image.FigmaMCP.chevronRight
                    .figmaMCPIconStyle(size: 16, semanticColor: Color.FigmaMCP.Semantic.foregroundPrimary)
            }
            .padding(.horizontal, 16)
            .frame(height: 32)
            .background(Color.FigmaMCP.Semantic.fogThin)
            .clipShape(RoundedRectangle(cornerRadius: 100))
        }
        .buttonStyle(PlainButtonStyle())
    }

    private var menu: some View {
        // Single container with all options, matching prototype exactly
        VStack(spacing: 0) {
            menuRow(
                image: Image.FigmaMCP.coverCreate,
                title: L10n.FeatureClipDetail.cover,
                subtitle: L10n.FeatureClipDetail.coverDescription,
                isLast: false
            ) {
                store.send(.coverTapped)
            }

            menuRow(
                image: Image.FigmaMCP.extendRight,
                title: L10n.FeatureClipDetail.extend,
                subtitle: L10n.FeatureClipDetail.extendDescription,
                isLast: true
            ) {
                store.send(.extendTapped)
            }
        }
        .background(Color.FigmaMCP.Semantic.fogThin)
        .clipShape(RoundedRectangle(cornerRadius: 16))
    }

    @ViewBuilder
    private func menuRow(image: Image, title: String, subtitle: String, isLast: Bool = false, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            HStack(spacing: 10) {
                // Icon
                image
                    .figmaMCPIconStyle(size: 24, semanticColor: Color.FigmaMCP.Semantic.foregroundPrimary)

                // Title and Description
                VStack(alignment: .leading, spacing: 0) {
                    Text(title)
                        .figmaMCPTypography(TypographyV1.FigmaMCP.mediumTitle)
                        .foregroundStyle(Color.FigmaMCP.Semantic.foregroundPrimary)
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .tracking(0.32)

                    Text(subtitle)
                        .figmaMCPTypography(TypographyV1.FigmaMCP.xSmallRegular)
                        .foregroundStyle(Color.FigmaMCP.Semantic.foregroundTertiary)
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .tracking(0.24)
                }

                // Chevron
                Image.FigmaMCP.chevronRight
                    .figmaMCPIconStyle(size: 16, semanticColor: Color.FigmaMCP.Semantic.foregroundPrimary)
            }
            .padding(16)
            .contentShape(.rect)
        }
        .buttonStyle(PlainButtonStyle())

        // Divider (except for last item)
        if !isLast {
            Rectangle()
                .fill(Color.FigmaMCP.Semantic.fogThick)
                .frame(height: 1)
                .padding(.leading, 50) // Align with text content
        }
    }
}
