import BackendEnvironmentClient
import ComposableArchitecture
import Foundation
import GenAPI

public struct Hook: Identifiable, Equatable, Hashable, Sendable {
    public enum Status: String, Codable {
        case submitted
        case queued
        case streaming
        case complete
        case error
        case undefined
        case renderedPassedModeration = "rendered_passed_moderation"
        case failed
        case renderedFailedModeration = "rendered_failed_moderation"
        case processing
        case rendering
    }

    public enum CreationSource: String, Codable {
        case userUpload = "user_upload"
        case backfillVideoCover = "backfill_video_cover"
    }

    public var id: String
    public var allowComments: Bool
    public var caption: String?
    public var clip: Clip?
    public var commentCount: Int
    public var createdAt: Date?
    public var currentUserLiked: Bool
    public var currentUserFollowsCreator: Bool
    public var endClipTimestamp: Double
    public var likeCount: Int
    public var lyricDisplay: LyricDisplay?
    public var originalClipId: String
    public var renderedVideoPreviewS3Id: String?
    public var renderedVideoPreviewUrl: String?
    public var renderedVideoS3Id: String?
    public var renderedVideoUrl: String?
    public var showLyrics: Bool
    public var startClipTimestamp: Double
    public var status: Status
    public var streamingUrl: String?
    public var thumbnailImageS3Id: String?
    public var thumbnailImageUrl: String?
    public var title: String
    public var updatedAt: Date?
    public var user: SimpleProfile?
    public var userId: Int
    public var videoDuration: Double
    public var viewCount: Int
    public var recommendationItemId: String?
    public var isDisliked: Bool
    public var creationSource: CreationSource
    public var contentRatingTags: [String]?
    public var videoUploadIds: [String]?

    public var isLiked: Bool {
        get { currentUserLiked }
        set {
            currentUserLiked = newValue
        }
    }

    public var isCreatorFollowed: Bool {
        get { currentUserFollowsCreator }
        set {
            currentUserFollowsCreator = newValue
        }
    }

    public init(
        id: String,
        allowComments: Bool = true,
        caption: String? = nil,
        clip: Clip? = nil,
        commentCount: Int = 0,
        createdAt: Date? = nil,
        currentUserLiked: Bool = false,
        currentUserFollowsCreator: Bool = false,
        endClipTimestamp: Double,
        likeCount: Int = 0,
        lyricDisplay: LyricDisplay? = nil,
        originalClipId: String,
        recommendationItemId: String? = nil,
        renderedVideoPreviewS3Id: String? = nil,
        renderedVideoPreviewUrl: String? = nil,
        renderedVideoS3Id: String? = nil,
        renderedVideoUrl: String? = nil,
        showLyrics: Bool = true,
        startClipTimestamp: Double,
        status: Hook.Status = .undefined,
        streamingUrl: String? = nil,
        thumbnailImageS3Id: String? = nil,
        thumbnailImageUrl: String? = nil,
        title: String,
        updatedAt: Date? = nil,
        user: SimpleProfile? = nil,
        userId: Int,
        videoDuration: Double,
        viewCount: Int = 0,
        isDisliked: Bool = false,
        creationSource: CreationSource = .userUpload,
        contentRatingTags: [String]? = nil,
        videoUploadIds: [String]? = nil
    ) {
        self.id = id
        self.allowComments = allowComments
        self.caption = caption
        self.clip = clip
        self.commentCount = commentCount
        self.createdAt = createdAt
        self.currentUserLiked = currentUserLiked
        self.currentUserFollowsCreator = currentUserFollowsCreator
        self.endClipTimestamp = endClipTimestamp
        self.likeCount = likeCount
        self.lyricDisplay = lyricDisplay
        self.originalClipId = originalClipId
        self.recommendationItemId = recommendationItemId
        self.renderedVideoPreviewS3Id = renderedVideoPreviewS3Id
        self.renderedVideoPreviewUrl = renderedVideoPreviewUrl
        self.renderedVideoS3Id = renderedVideoS3Id
        self.renderedVideoUrl = renderedVideoUrl
        self.showLyrics = showLyrics
        self.startClipTimestamp = startClipTimestamp
        self.status = status
        self.streamingUrl = streamingUrl
        self.thumbnailImageS3Id = thumbnailImageS3Id
        self.thumbnailImageUrl = thumbnailImageUrl
        self.title = title
        self.updatedAt = updatedAt
        self.user = user
        self.userId = userId
        self.videoDuration = videoDuration
        self.viewCount = viewCount
        self.isDisliked = isDisliked
        self.creationSource = creationSource
        self.contentRatingTags = contentRatingTags
        self.videoUploadIds = videoUploadIds
    }
}

public extension Hook {
    /// Indicates whether this hook should be displayed in grids and feeds to viewers
    /// Only hooks that have passed moderation and were uploaded by users are shown
    var isPublicDisplayable: Bool {
        status == .renderedPassedModeration && creationSource == .userUpload
    }

    /// Indicates whether this hook should be displayed in grids and feeds to the creator of the Hook
    var isUserDisplayable: Bool {
        (status == .renderedPassedModeration || status == .renderedFailedModeration || status == .error) && creationSource == .userUpload
    }
}

public extension Array where Element == Hook {
    /// Filters hooks to only include those that should be displayed to users
    /// Returns hooks that have passed moderation and were uploaded by users
    var publicDisplayableHooks: [Hook] {
        filter { $0.isPublicDisplayable }
    }

    /// Filters hooks to only include those that should be displayed to the Hook creator
    /// Returns hooks that were uploaded by the creator
    var userDisplayableHooks: [Hook] {
        filter { $0.isUserDisplayable }
    }
}

public extension Hook {
    init(_ remote: GenAPI.VideoHookSchema) throws {
        self.id = remote.id
        self.allowComments = remote.allowComments
        self.caption = remote.caption
        self.clip = try remote.clip.map { try Clip($0) }
        self.commentCount = remote.commentCount ?? 0

        // Parse date strings
        let dateFormatter = ISO8601DateFormatter()
        dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
        self.createdAt = dateFormatter.date(from: remote.createdAt)
        self.updatedAt = dateFormatter.date(from: remote.updatedAt)

        self.currentUserLiked = remote.currentUserLiked
        self.currentUserFollowsCreator = remote.currentUserFollowsCreator
        self.endClipTimestamp = remote.endClipTimestamp
        self.likeCount = remote.likeCount
        self.lyricDisplay = remote.lyricDisplay.map { LyricDisplay($0) }
        self.originalClipId = remote.originalClipId
        self.recommendationItemId = remote.recommendationItemId
        self.renderedVideoPreviewS3Id = remote.renderedVideoPreviewS3Id
        self.renderedVideoPreviewUrl = remote.renderedVideoPreviewUrl
        self.renderedVideoS3Id = remote.renderedVideoS3Id
        self.renderedVideoUrl = remote.renderedVideoUrl
        self.showLyrics = remote.showLyrics
        self.startClipTimestamp = remote.startClipTimestamp
        self.status = Hook.Status(rawValue: remote.status.rawValue) ?? .undefined
        self.streamingUrl = remote.videoStreamingResolutions?.first?.url
        self.thumbnailImageS3Id = remote.thumbnailImageS3Id
        self.thumbnailImageUrl = remote.thumbnailImageUrl
        self.title = remote.title
        self.user = try remote.user.map { try SimpleProfile($0) }
        self.userId = remote.userId
        self.videoDuration = remote.videoDuration
        self.viewCount = remote.viewCount
        self.isDisliked = remote.currentUserDisliked
        self.creationSource = Hook.CreationSource(
            rawValue: remote.creationSource?.rawValue ?? Hook.CreationSource.userUpload.rawValue
        ) ?? .userUpload
        self.contentRatingTags = remote.contentRatingTags
        self.videoUploadIds = remote.videoUploadIds
    }

    var fallbackShareURL: URL {
        let baseUrl = BackendEnvironmentProvider.currentConfiguration().webEndpointHost
        return URL(string: "https://\(baseUrl)/hook/\(id)")!
    }
}

#if DEBUG
    public extension Hook {
        static func mock(id: String = UUID().uuidString) -> Hook {
            Hook(
                id: id,
                allowComments: true,
                caption: "Check out this amazing hook!",
                clip: Clip.mock(),
                commentCount: 123,
                createdAt: Date(),
                currentUserLiked: false,
                currentUserFollowsCreator: false,
                endClipTimestamp: 30.0,
                likeCount: 25,
                lyricDisplay: .bottomLeftLine,
                originalClipId: UUID().uuidString,
                renderedVideoPreviewUrl: "https://example.com/preview.mp4",
                renderedVideoUrl: "https://example.com/video.mp4",
                showLyrics: true,
                startClipTimestamp: 0.0,
                status: .complete,
                thumbnailImageUrl: "https://example.com/thumbnail.jpg",
                title: "Mock Hook Title",
                updatedAt: Date(),
                userId: 123,
                videoDuration: 30.0,
                viewCount: 150,
                isDisliked: false,
                creationSource: .userUpload
            )
        }
    }
#endif
