//
//  Bookmark.swift
//  Yattee
//
//  SwiftData model for bookmarked/favorited videos.
//

import Foundation
import SwiftData

/// Represents a bookmarked video for later viewing.
@Model
final class Bookmark {
    // MARK: - Video Identity

    /// The video ID string (YouTube ID or PeerTube UUID).
    var videoID: String = ""

    /// The content source raw value for encoding ("global", "federated", "extracted").
    var sourceRawValue: String = "global"

    /// For global sources: the provider name (e.g., "youtube", "dailymotion").
    var globalProvider: String?

    /// For PeerTube: the instance URL string.
    var instanceURLString: String?

    /// For PeerTube: the UUID.
    var peertubeUUID: String?

    /// For external sources: the extractor name (e.g., "vimeo", "twitter").
    var externalExtractor: String?

    /// For external sources: the original URL for re-extraction.
    var externalURLString: String?

    // MARK: - Video Metadata (cached for offline display)

    /// The video title.
    var title: String = ""

    /// The channel/author name.
    var authorName: String = ""

    /// The channel/author ID.
    var authorID: String = ""

    /// Video duration in seconds.
    var duration: TimeInterval = 0

    /// Thumbnail URL string.
    var thumbnailURLString: String?

    /// Whether this is a live stream.
    var isLive: Bool = false

    /// View count if available.
    var viewCount: Int?

    /// When the video was published.
    var publishedAt: Date?

    /// Human-readable published date from the API.
    var publishedText: String?

    // MARK: - Bookmark Metadata

    /// When this bookmark was created.
    var createdAt: Date = Date()

    /// Optional user note/comment.
    var note: String?

    /// When the note was last modified.
    var noteModifiedAt: Date?

    /// User-defined tags for categorizing the bookmark.
    var tags: [String] = []

    /// When the tags were last modified.
    var tagsModifiedAt: Date?

    /// Sort order for manual ordering.
    var sortOrder: Int = 0

    // MARK: - Initialization

    init(
        videoID: String,
        sourceRawValue: String,
        globalProvider: String? = nil,
        instanceURLString: String? = nil,
        peertubeUUID: String? = nil,
        externalExtractor: String? = nil,
        externalURLString: String? = nil,
        title: String,
        authorName: String,
        authorID: String,
        duration: TimeInterval,
        thumbnailURLString: String? = nil,
        isLive: Bool = false,
        viewCount: Int? = nil,
        publishedAt: Date? = nil,
        publishedText: String? = nil,
        note: String? = nil,
        noteModifiedAt: Date? = nil,
        tags: [String] = [],
        tagsModifiedAt: Date? = nil,
        sortOrder: Int = 0
    ) {
        self.videoID = videoID
        self.sourceRawValue = sourceRawValue
        self.globalProvider = globalProvider
        self.instanceURLString = instanceURLString
        self.peertubeUUID = peertubeUUID
        self.externalExtractor = externalExtractor
        self.externalURLString = externalURLString
        self.title = title
        self.authorName = authorName
        self.authorID = authorID
        self.duration = duration
        self.thumbnailURLString = thumbnailURLString
        self.isLive = isLive
        self.viewCount = viewCount
        self.publishedAt = publishedAt
        self.publishedText = publishedText
        self.note = note
        self.noteModifiedAt = noteModifiedAt
        self.tags = tags
        self.tagsModifiedAt = tagsModifiedAt
        self.sortOrder = sortOrder
        self.createdAt = Date()
    }

    // MARK: - Computed Properties

    /// The content source for this bookmark.
    var contentSource: ContentSource {
        if sourceRawValue == "global" {
            return .global(provider: globalProvider ?? ContentSource.youtubeProvider)
        } else if sourceRawValue == "federated",
                  let urlString = instanceURLString,
                  let url = URL(string: urlString) {
            return .federated(provider: ContentSource.peertubeProvider, instance: url)
        } else if sourceRawValue == "extracted",
                  let extractor = externalExtractor,
                  let urlString = externalURLString,
                  let url = URL(string: urlString) {
            return .extracted(extractor: extractor, originalURL: url)
        }
        return .global(provider: globalProvider ?? ContentSource.youtubeProvider)
    }

    /// The thumbnail URL if available.
    var thumbnailURL: URL? {
        thumbnailURLString.flatMap { URL(string: $0) }
    }

    /// Formatted duration string.
    var formattedDuration: String {
        guard !isLive else { return String(localized: "video.badge.live") }
        guard duration > 0 else { return "" }

        let hours = Int(duration) / 3600
        let minutes = (Int(duration) % 3600) / 60
        let seconds = Int(duration) % 60

        if hours > 0 {
            return String(format: "%d:%02d:%02d", hours, minutes, seconds)
        } else {
            return String(format: "%d:%02d", minutes, seconds)
        }
    }

    /// Formatted view count string.
    var formattedViewCount: String? {
        guard let viewCount else { return nil }
        return CountFormatter.compact(viewCount)
    }

    /// Formatted published date, preferring parsed Date over API-provided text.
    var formattedPublishedDate: String? {
        if let publishedAt {
            let formatter = RelativeDateTimeFormatter()
            formatter.unitsStyle = .full
            return formatter.localizedString(for: publishedAt, relativeTo: Date())
        }
        return publishedText
    }

    /// Converts this bookmark to a Video model for playback.
    func toVideo() -> Video {
        let videoIDObj: VideoID
        switch contentSource {
        case .global(let provider):
            videoIDObj = VideoID(source: .global(provider: provider), videoID: videoID)
        case .federated(let provider, let instance):
            videoIDObj = VideoID(source: .federated(provider: provider, instance: instance), videoID: videoID, uuid: peertubeUUID)
        case .extracted(let extractor, let originalURL):
            videoIDObj = VideoID(source: .extracted(extractor: extractor, originalURL: originalURL), videoID: videoID)
        }

        let author = Author(
            id: authorID,
            name: authorName,
            thumbnailURL: nil,
            subscriberCount: nil
        )

        return Video(
            id: videoIDObj,
            title: title,
            description: nil,
            author: author,
            duration: duration,
            publishedAt: publishedAt,
            publishedText: publishedText,
            viewCount: viewCount,
            likeCount: nil,
            thumbnails: Thumbnail.fallbackChain(for: thumbnailURL),
            isLive: isLive,
            isUpcoming: false,
            scheduledStartTime: nil
        )
    }
}

// MARK: - Factory Methods

extension Bookmark {
    /// Creates a Bookmark from a Video model.
    static func from(video: Video, tags: [String] = [], tagsModifiedAt: Date? = nil, sortOrder: Int = 0) -> Bookmark {
        let sourceRaw: String
        var provider: String?
        var instanceURL: String?
        var uuid: String?
        var extractor: String?
        var externalURL: String?

        switch video.id.source {
        case .global(let prov):
            sourceRaw = "global"
            provider = prov
        case .federated(_, let instance):
            sourceRaw = "federated"
            instanceURL = instance.absoluteString
            uuid = video.id.uuid
        case .extracted(let ext, let originalURL):
            sourceRaw = "extracted"
            extractor = ext
            externalURL = originalURL.absoluteString
        }

        return Bookmark(
            videoID: video.id.videoID,
            sourceRawValue: sourceRaw,
            globalProvider: provider,
            instanceURLString: instanceURL,
            peertubeUUID: uuid,
            externalExtractor: extractor,
            externalURLString: externalURL,
            title: video.title,
            authorName: video.author.name,
            authorID: video.author.id,
            duration: video.duration,
            thumbnailURLString: video.bestThumbnail?.url.absoluteString,
            isLive: video.isLive,
            viewCount: video.viewCount,
            publishedAt: video.publishedAt,
            publishedText: video.publishedText,
            tags: tags,
            tagsModifiedAt: tagsModifiedAt,
            sortOrder: sortOrder
        )
    }
}

// MARK: - Preview Support

extension Bookmark {
    /// A sample bookmark for SwiftUI previews.
    static var preview: Bookmark {
        Bookmark(
            videoID: "dQw4w9WgXcQ",
            sourceRawValue: "global",
            globalProvider: "youtube",
            title: "Sample Video Title",
            authorName: "Sample Channel",
            authorID: "UC123",
            duration: 212,
            thumbnailURLString: "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
            isLive: false,
            viewCount: 1_234_567,
            publishedAt: Date().addingTimeInterval(-86400 * 3),
            publishedText: "3 days ago",
            note: "Great video about SwiftUI patterns and best practices",
            tags: ["Swift", "iOS", "Tutorial", "SwiftUI", "Xcode"]
        )
    }
}
