import Foundation
import SwiftData
import SwiftUI

@Model
final class BusinessCard {
    var id: UUID
    var displayName: String
    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(),
        displayName: String = "",
        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.displayName = displayName
        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: ", ")
        }
    }
    
    /// Computed display name with special formatting:
    /// - Preferred name in quotes: "Bubba"
    /// - Maiden name in parentheses: (Hackney)
    /// - Pronouns in parentheses: (He/Him)
    var computedDisplayName: String {
        if !displayName.isEmpty { return displayName }
        
        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: " ")
    }
    
    /// Returns the simple name for display (without formatting) - used for vCard
    var simpleName: String {
        if !displayName.isEmpty { return displayName }
        let parts = [prefix, firstName, middleName, lastName, suffix].filter { !$0.isEmpty }
        return parts.joined(separator: " ")
    }
    
    /// Returns the name to display (preferredName or first/last name)
    var effectiveDisplayName: String {
        if !preferredName.isEmpty { return preferredName }
        let parts = [firstName, lastName].filter { !$0.isEmpty }
        return parts.isEmpty ? computedDisplayName : parts.joined(separator: " ")
    }

    @MainActor
    var vCardPayload: String {
        var lines = [
            "BEGIN:VCARD",
            "VERSION:3.0"
        ]
        
        // N: Structured name - REQUIRED for proper contact import
        let structuredName = [lastName, firstName, middleName, prefix, suffix]
            .map { escapeVCardValue($0) }
            .joined(separator: ";")
        lines.append("N:\(structuredName)")
        
        // FN: Formatted name
        let formattedName = simpleName.isEmpty ? displayName : simpleName
        lines.append("FN:\(escapeVCardValue(formattedName))")
        
        // NICKNAME: Preferred name
        if !preferredName.isEmpty {
            lines.append("NICKNAME:\(escapeVCardValue(preferredName))")
        }
        
        // ORG: Organization
        if !company.isEmpty {
            if !department.isEmpty {
                lines.append("ORG:\(escapeVCardValue(company));\(escapeVCardValue(department))")
            } else {
                lines.append("ORG:\(escapeVCardValue(company))")
            }
        }
        
        // TITLE: Job title/role
        if !role.isEmpty {
            lines.append("TITLE:\(escapeVCardValue(role))")
        }
        
        // Contact fields from the array
        for field in orderedContactFields {
            let value = field.value.trimmingCharacters(in: .whitespacesAndNewlines)
            guard !value.isEmpty else { continue }
            
            switch field.typeId {
            case "email":
                let typeLabel = field.title.isEmpty ? "WORK" : field.title.uppercased()
                lines.append("EMAIL;TYPE=\(typeLabel):\(escapeVCardValue(value))")
            case "phone":
                let typeLabel = field.title.isEmpty ? "CELL" : field.title.uppercased()
                lines.append("TEL;TYPE=\(typeLabel):\(escapeVCardValue(value))")
            case "website":
                lines.append("URL:\(escapeVCardValue(value))")
            case "address":
                // Use structured PostalAddress for proper VCard ADR format
                if let postalAddress = field.postalAddress {
                    let typeLabel = field.title.isEmpty ? "WORK" : field.title.uppercased()
                    lines.append(postalAddress.vCardADRLine(type: typeLabel))
                } else {
                    // Fallback for legacy data
                    lines.append("ADR;TYPE=WORK:;;\(escapeVCardValue(value));;;;")
                }
            case "linkedIn":
                lines.append("X-SOCIALPROFILE;TYPE=linkedin:\(escapeVCardValue(value))")
            case "twitter":
                lines.append("X-SOCIALPROFILE;TYPE=twitter:\(escapeVCardValue(value))")
            case "instagram":
                lines.append("X-SOCIALPROFILE;TYPE=instagram:\(escapeVCardValue(value))")
            case "facebook":
                lines.append("X-SOCIALPROFILE;TYPE=facebook:\(escapeVCardValue(value))")
            case "tiktok":
                lines.append("X-SOCIALPROFILE;TYPE=tiktok:\(escapeVCardValue(value))")
            case "github":
                lines.append("X-SOCIALPROFILE;TYPE=github:\(escapeVCardValue(value))")
            case "threads":
                lines.append("X-SOCIALPROFILE;TYPE=threads:\(escapeVCardValue(value))")
            case "telegram":
                lines.append("X-SOCIALPROFILE;TYPE=telegram:\(escapeVCardValue(value))")
            case "bluesky":
                lines.append("X-SOCIALPROFILE;TYPE=bluesky:\(escapeVCardValue(value))")
            case "mastodon":
                lines.append("X-SOCIALPROFILE;TYPE=mastodon:\(escapeVCardValue(value))")
            case "youtube":
                lines.append("X-SOCIALPROFILE;TYPE=youtube:\(escapeVCardValue(value))")
            case "twitch":
                lines.append("X-SOCIALPROFILE;TYPE=twitch:\(escapeVCardValue(value))")
            case "reddit":
                lines.append("X-SOCIALPROFILE;TYPE=reddit:\(escapeVCardValue(value))")
            case "snapchat":
                lines.append("X-SOCIALPROFILE;TYPE=snapchat:\(escapeVCardValue(value))")
            case "pinterest":
                lines.append("X-SOCIALPROFILE;TYPE=pinterest:\(escapeVCardValue(value))")
            case "discord":
                lines.append("X-SOCIALPROFILE;TYPE=discord:\(escapeVCardValue(value))")
            case "slack":
                lines.append("X-SOCIALPROFILE;TYPE=slack:\(escapeVCardValue(value))")
            case "whatsapp":
                lines.append("X-SOCIALPROFILE;TYPE=whatsapp:\(escapeVCardValue(value))")
            case "signal":
                lines.append("X-SOCIALPROFILE;TYPE=signal:\(escapeVCardValue(value))")
            case "venmo":
                lines.append("X-SOCIALPROFILE;TYPE=venmo:\(escapeVCardValue(value))")
            case "cashApp":
                lines.append("X-SOCIALPROFILE;TYPE=cashapp:\(escapeVCardValue(value))")
            case "paypal":
                lines.append("X-SOCIALPROFILE;TYPE=paypal:\(escapeVCardValue(value))")
            case "calendly":
                lines.append("URL;TYPE=calendly:\(escapeVCardValue(value))")
            case "customLink":
                let label = field.title.isEmpty ? "OTHER" : field.title.uppercased()
                lines.append("URL;TYPE=\(label):\(escapeVCardValue(value))")
            default:
                if value.contains("://") || value.contains(".") {
                    lines.append("URL:\(escapeVCardValue(value))")
                }
            }
        }
        
        // NOTE: Bio, headline, and accreditations
        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)") }
        if !notes.isEmpty {
            lines.append("NOTE:\(escapeVCardValue(notes.joined(separator: "\\n")))")
        }
        
        lines.append("END:VCARD")
        return lines.joined(separator: "\r\n")
    }
    
    /// 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 {
    @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(
            displayName: "Daniel Sullivan",
            role: "Property Developer",
            company: "WR Construction",
            label: "Work",
            isDefault: true,
            themeName: "Coral",
            layoutStyleRawValue: "split",
            headerLayoutRawValue: "coverWithAvatarAndLogo",
            avatarSystemName: "person.crop.circle",
            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(
            displayName: "Maya Chen",
            role: "Creative Lead",
            company: "Signal Studio",
            label: "Creative",
            isDefault: false,
            themeName: "Midnight",
            layoutStyleRawValue: "stacked",
            headerLayoutRawValue: "logoBanner",
            avatarSystemName: "sparkles",
            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(
            displayName: "DJ Michaels",
            role: "DJ",
            company: "Live Sessions",
            label: "Music",
            isDefault: false,
            themeName: "Ocean",
            layoutStyleRawValue: "photo",
            headerLayoutRawValue: "profileBanner",
            avatarSystemName: "music.mic",
            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: "")
    }
}
