import Foundation
import SwiftData
import SwiftUI

@Model
final class BusinessCard {
    var id: UUID
    var role: String
    var company: String
    var label: String
    var isDefault: Bool
    var themeName: String
    var layoutStyleRawValue: String
    var headerLayoutRawValue: String
    var avatarSystemName: String
    var createdAt: Date
    var updatedAt: Date
    
    // Enhanced profile fields
    var prefix: String
    var firstName: String
    var middleName: String
    var lastName: String
    var suffix: String
    var maidenName: String
    var preferredName: String
    var pronouns: String
    var department: String
    var headline: String
    var bio: String
    var accreditations: String
    
    // Profile photo stored as Data (JPEG)
    @Attribute(.externalStorage) var photoData: Data?
    
    // Cover photo for banner background stored as Data (JPEG)
    @Attribute(.externalStorage) var coverPhotoData: Data?
    
    // Company logo stored as Data (PNG)
    @Attribute(.externalStorage) var logoData: Data?
    
    // Contact fields array (ordered, supports multiples)
    @Relationship(deleteRule: .cascade, inverse: \ContactField.card)
    var contactFields: [ContactField]? = []

    init(
        id: UUID = UUID(),
        role: String = "",
        company: String = "",
        label: String = "Work",
        isDefault: Bool = false,
        themeName: String = "Coral",
        layoutStyleRawValue: String = "stacked",
        headerLayoutRawValue: String = "profileBanner",
        avatarSystemName: String = "person.crop.circle",
        createdAt: Date = .now,
        updatedAt: Date = .now,
        prefix: String = "",
        firstName: String = "",
        middleName: String = "",
        lastName: String = "",
        suffix: String = "",
        maidenName: String = "",
        preferredName: String = "",
        pronouns: String = "",
        department: String = "",
        headline: String = "",
        bio: String = "",
        accreditations: String = "",
        photoData: Data? = nil,
        coverPhotoData: Data? = nil,
        logoData: Data? = nil
    ) {
        self.id = id
        self.role = role
        self.company = company
        self.label = label
        self.isDefault = isDefault
        self.themeName = themeName
        self.layoutStyleRawValue = layoutStyleRawValue
        self.headerLayoutRawValue = headerLayoutRawValue
        self.avatarSystemName = avatarSystemName
        self.createdAt = createdAt
        self.updatedAt = updatedAt
        self.prefix = prefix
        self.firstName = firstName
        self.middleName = middleName
        self.lastName = lastName
        self.suffix = suffix
        self.maidenName = maidenName
        self.preferredName = preferredName
        self.pronouns = pronouns
        self.department = department
        self.headline = headline
        self.bio = bio
        self.accreditations = accreditations
        self.photoData = photoData
        self.coverPhotoData = coverPhotoData
        self.logoData = logoData
    }

    @MainActor
    var theme: CardTheme {
        get { CardTheme(named: themeName) }
        set { themeName = newValue.name }
    }

    var layoutStyle: CardLayoutStyle {
        get { CardLayoutStyle(rawValue: layoutStyleRawValue) ?? .stacked }
        set { layoutStyleRawValue = newValue.rawValue }
    }
    
    var headerLayout: CardHeaderLayout {
        get { CardHeaderLayout(rawValue: headerLayoutRawValue) ?? .profileBanner }
        set { headerLayoutRawValue = newValue.rawValue }
    }
    
    /// Returns true if the card has a profile photo.
    var hasProfilePhoto: Bool { photoData != nil }
    
    /// Returns true if the card has a cover photo.
    var hasCoverPhoto: Bool { coverPhotoData != nil }
    
    /// Returns true if the card has a company logo.
    var hasLogo: Bool { logoData != nil }
    
    /// Returns the suggested header layout based on available images.
    var suggestedHeaderLayout: CardHeaderLayout {
        CardHeaderLayout.suggested(
            hasProfile: hasProfilePhoto,
            hasCover: hasCoverPhoto,
            hasLogo: hasLogo
        )
    }

    var shareURL: URL {
        let base = URL(string: "https://cards.example") ?? URL.documentsDirectory
        return base.appending(path: id.uuidString)
    }
    
    /// Ordered contact fields (non-nil, sorted by orderIndex)
    var orderedContactFields: [ContactField] {
        (contactFields ?? []).sorted { $0.orderIndex < $1.orderIndex }
    }
    
    /// Adds a new contact field
    func addContactField(typeId: String, value: String = "", title: String = "") {
        let newIndex = (contactFields ?? []).count
        let field = ContactField(typeId: typeId, value: value, title: title, orderIndex: newIndex)
        field.card = self
        if contactFields == nil {
            contactFields = []
        }
        contactFields?.append(field)
    }
    
    /// Adds a new contact field from ContactFieldType
    func addContactField(_ type: ContactFieldType, value: String = "", title: String = "") {
        addContactField(typeId: type.id, value: value, title: title)
    }
    
    /// Removes a contact field
    func removeContactField(_ field: ContactField) {
        contactFields?.removeAll { $0.id == field.id }
        reorderContactFields()
    }
    
    /// Reorders contact fields after changes
    func reorderContactFields() {
        for (index, field) in orderedContactFields.enumerated() {
            field.orderIndex = index
        }
    }
    
    /// Gets the first contact field of a given type
    func firstContactField(ofType typeId: String) -> ContactField? {
        orderedContactFields.first { $0.typeId == typeId }
    }
    
    /// Gets all contact fields of a given type
    func contactFields(ofType typeId: String) -> [ContactField] {
        orderedContactFields.filter { $0.typeId == typeId }
    }
    
    /// Returns accreditations as an array (stored as comma-separated string)
    var accreditationsList: [String] {
        get {
            accreditations.split(separator: ",")
                .map { $0.trimmingCharacters(in: .whitespaces) }
                .filter { !$0.isEmpty }
        }
        set {
            accreditations = newValue.joined(separator: ", ")
        }
    }
    
    // MARK: - Name Properties (Single Source of Truth)
    
    /// The full formatted name - THIS IS THE SINGLE SOURCE OF TRUTH for display.
    /// Always computed from individual name fields.
    /// Includes special formatting: preferred name in quotes, maiden name and pronouns in parentheses.
    var fullName: String {
        var parts: [String] = []
        
        if !prefix.isEmpty { parts.append(prefix) }
        if !firstName.isEmpty { parts.append(firstName) }
        if !preferredName.isEmpty { parts.append("\"\(preferredName)\"") }
        if !middleName.isEmpty { parts.append(middleName) }
        if !lastName.isEmpty { parts.append(lastName) }
        if !suffix.isEmpty { parts.append(suffix) }
        if !maidenName.isEmpty { parts.append("(\(maidenName))") }
        if !pronouns.isEmpty { parts.append("(\(pronouns))") }
        
        return parts.joined(separator: " ")
    }
    
    /// Plain name for vCard export (no quotes or parentheses formatting).
    /// Used when generating contact cards for sharing.
    var vCardName: String {
        [prefix, firstName, middleName, lastName, suffix]
            .filter { !$0.isEmpty }
            .joined(separator: " ")
    }

    /// Display-friendly preferred name fallback.
    var displayName: String {
        if !preferredName.isEmpty { return preferredName }
        if !firstName.isEmpty { return firstName }
        return fullName
    }

    @MainActor
    var vCardPayload: String {
        buildVCardPayload(includePhotoData: nil)
    }
    
    /// Generates a vCard payload with embedded profile photo for file-based sharing.
    /// This payload is too large for QR codes but works perfectly for AirDrop,
    /// Messages, Email attachments, and other file-based sharing methods.
    @MainActor
    var vCardFilePayload: String {
        buildVCardPayload(includePhotoData: photoData)
    }

    private var vCardStructuredName: String {
        [lastName, firstName, middleName, prefix, suffix]
            .map(escapeVCardValue)
            .joined(separator: ";")
    }

    private var vCardNoteEntries: [String] {
        var notes: [String] = []
        if !headline.isEmpty { notes.append(headline) }
        if !bio.isEmpty { notes.append(bio) }
        if !accreditations.isEmpty { notes.append("Credentials: \(accreditations)") }
        if !pronouns.isEmpty { notes.append("Pronouns: \(pronouns)") }
        return notes
    }

    @MainActor
    private func buildVCardPayload(includePhotoData: Data?) -> String {
        var lines = ["BEGIN:VCARD", "VERSION:3.0"]
        lines.append("N:\(vCardStructuredName)")
        lines.append("FN:\(escapeVCardValue(vCardName))")

        if let includePhotoData {
            lines.append("PHOTO;ENCODING=b;TYPE=JPEG:\(includePhotoData.base64EncodedString())")
        }

        if !preferredName.isEmpty {
            lines.append("NICKNAME:\(escapeVCardValue(preferredName))")
        }

        if !company.isEmpty {
            if !department.isEmpty {
                lines.append("ORG:\(escapeVCardValue(company));\(escapeVCardValue(department))")
            } else {
                lines.append("ORG:\(escapeVCardValue(company))")
            }
        }

        if !role.isEmpty {
            lines.append("TITLE:\(escapeVCardValue(role))")
        }

        for field in orderedContactFields {
            let value = field.value.trimmingCharacters(in: .whitespacesAndNewlines)
            guard !value.isEmpty else { continue }
            lines.append(contentsOf: vCardLines(for: field, value: value))
        }

        if !vCardNoteEntries.isEmpty {
            lines.append("NOTE:\(escapeVCardValue(vCardNoteEntries.joined(separator: "\\n")))")
        }

        lines.append("END:VCARD")
        return lines.joined(separator: "\r\n")
    }

    @MainActor
    private func vCardLines(for field: ContactField, value: String) -> [String] {
        switch field.typeId {
        case "email":
            let typeLabel = field.title.isEmpty ? "WORK" : field.title.uppercased()
            return ["EMAIL;TYPE=\(typeLabel):\(escapeVCardValue(value))"]
        case "phone":
            let typeLabel = field.title.isEmpty ? "CELL" : field.title.uppercased()
            return ["TEL;TYPE=\(typeLabel):\(escapeVCardValue(value))"]
        case "website":
            return ["URL:\(escapeVCardValue(value))"]
        case "address":
            if let postalAddress = field.postalAddress {
                let typeLabel = field.title.isEmpty ? "WORK" : field.title.uppercased()
                return [postalAddress.vCardADRLine(type: typeLabel)]
            }
            return ["ADR;TYPE=WORK:;;\(escapeVCardValue(value));;;;"]
        case "linkedIn":
            return ["X-SOCIALPROFILE;TYPE=linkedin:\(escapeVCardValue(value))"]
        case "twitter":
            return ["X-SOCIALPROFILE;TYPE=twitter:\(escapeVCardValue(value))"]
        case "instagram":
            return ["X-SOCIALPROFILE;TYPE=instagram:\(escapeVCardValue(value))"]
        case "facebook":
            return ["X-SOCIALPROFILE;TYPE=facebook:\(escapeVCardValue(value))"]
        case "tiktok":
            return ["X-SOCIALPROFILE;TYPE=tiktok:\(escapeVCardValue(value))"]
        case "github":
            return ["X-SOCIALPROFILE;TYPE=github:\(escapeVCardValue(value))"]
        case "threads":
            return ["X-SOCIALPROFILE;TYPE=threads:\(escapeVCardValue(value))"]
        case "telegram":
            return ["X-SOCIALPROFILE;TYPE=telegram:\(escapeVCardValue(value))"]
        case "bluesky":
            return ["X-SOCIALPROFILE;TYPE=bluesky:\(escapeVCardValue(value))"]
        case "mastodon":
            return ["X-SOCIALPROFILE;TYPE=mastodon:\(escapeVCardValue(value))"]
        case "youtube":
            return ["X-SOCIALPROFILE;TYPE=youtube:\(escapeVCardValue(value))"]
        case "twitch":
            return ["X-SOCIALPROFILE;TYPE=twitch:\(escapeVCardValue(value))"]
        case "reddit":
            return ["X-SOCIALPROFILE;TYPE=reddit:\(escapeVCardValue(value))"]
        case "snapchat":
            return ["X-SOCIALPROFILE;TYPE=snapchat:\(escapeVCardValue(value))"]
        case "pinterest":
            return ["X-SOCIALPROFILE;TYPE=pinterest:\(escapeVCardValue(value))"]
        case "discord":
            return ["X-SOCIALPROFILE;TYPE=discord:\(escapeVCardValue(value))"]
        case "slack":
            return ["X-SOCIALPROFILE;TYPE=slack:\(escapeVCardValue(value))"]
        case "whatsapp":
            return ["X-SOCIALPROFILE;TYPE=whatsapp:\(escapeVCardValue(value))"]
        case "signal":
            return ["X-SOCIALPROFILE;TYPE=signal:\(escapeVCardValue(value))"]
        case "venmo":
            return ["X-SOCIALPROFILE;TYPE=venmo:\(escapeVCardValue(value))"]
        case "cashApp":
            return ["X-SOCIALPROFILE;TYPE=cashapp:\(escapeVCardValue(value))"]
        case "paypal":
            return ["X-SOCIALPROFILE;TYPE=paypal:\(escapeVCardValue(value))"]
        case "calendly":
            return ["URL;TYPE=calendly:\(escapeVCardValue(value))"]
        case "customLink":
            let label = field.title.isEmpty ? "OTHER" : field.title.uppercased()
            return ["URL;TYPE=\(label):\(escapeVCardValue(value))"]
        default:
            if value.contains("://") || value.contains(".") {
                return ["URL:\(escapeVCardValue(value))"]
            }
            return []
        }
    }

    /// Escapes special characters for vCard format
    private func escapeVCardValue(_ value: String) -> String {
        value
            .replacing("\\", with: "\\\\")
            .replacing(",", with: "\\,")
            .replacing(";", with: "\\;")
            .replacing("\n", with: "\\n")
    }
}

extension BusinessCard: VCardPayloadProviding {}

extension BusinessCard {
    @MainActor
    static func createSamples(in context: ModelContext) {
        // Sample 1: Property Developer - Uses coverWithAvatarAndLogo layout
        // Best when: Has cover, logo, and profile - logo centered on cover
        let sample1 = BusinessCard(
            role: "Property Developer",
            company: "WR Construction",
            label: "Work",
            isDefault: true,
            themeName: "Coral",
            layoutStyleRawValue: "split",
            headerLayoutRawValue: "coverWithAvatarAndLogo",
            avatarSystemName: "person.crop.circle",
            firstName: "Daniel",
            lastName: "Sullivan",
            pronouns: "he/him",
            bio: "Building the future of Dallas real estate"
        )
        context.insert(sample1)
        sample1.addContactField(.email, value: "daniel@wrconstruction.co", title: "Work")
        sample1.addContactField(.phone, value: "+1 (214) 987-7810", title: "Cell")
        sample1.addContactField(.website, value: "wrconstruction.co", title: "")
        sample1.addContactField(.address, value: "Dallas, TX", title: "Work")
        sample1.addContactField(.linkedIn, value: "linkedin.com/in/danielsullivan", title: "")
        
        // Sample 2: Creative Lead - Uses logoBanner layout
        // Best when: Strong logo, no cover needed
        let sample2 = BusinessCard(
            role: "Creative Lead",
            company: "Signal Studio",
            label: "Creative",
            isDefault: false,
            themeName: "Midnight",
            layoutStyleRawValue: "stacked",
            headerLayoutRawValue: "logoBanner",
            avatarSystemName: "sparkles",
            firstName: "Maya",
            lastName: "Chen",
            pronouns: "she/her",
            bio: "Designing experiences that matter"
        )
        context.insert(sample2)
        sample2.addContactField(.email, value: "maya@signal.studio", title: "Work")
        sample2.addContactField(.phone, value: "+1 (312) 404-2211", title: "Cell")
        sample2.addContactField(.website, value: "signal.studio", title: "")
        sample2.addContactField(.address, value: "Chicago, IL", title: "Work")
        sample2.addContactField(.twitter, value: "twitter.com/mayachen", title: "")
        sample2.addContactField(.instagram, value: "instagram.com/mayachen.design", title: "")
        
        // Sample 3: DJ - Uses profileBanner layout
        // Best when: Strong profile photo, personal brand
        let sample3 = BusinessCard(
            role: "DJ",
            company: "Live Sessions",
            label: "Music",
            isDefault: false,
            themeName: "Ocean",
            layoutStyleRawValue: "photo",
            headerLayoutRawValue: "profileBanner",
            avatarSystemName: "music.mic",
            firstName: "DJ",
            lastName: "Michaels",
            bio: "Bringing the beats to your events"
        )
        context.insert(sample3)
        sample3.addContactField(.email, value: "dj@livesessions.fm", title: "Work")
        sample3.addContactField(.phone, value: "+1 (646) 222-3300", title: "Cell")
        sample3.addContactField(.website, value: "livesessions.fm", title: "")
        sample3.addContactField(.address, value: "New York, NY", title: "Work")
        sample3.addContactField(.instagram, value: "instagram.com/djmichaels", title: "")
        sample3.addContactField(.tiktok, value: "tiktok.com/@djmichaels", title: "")
    }
}
