import Foundation
import SwiftData

@Model
final class Contact {
    var id: UUID
    var name: String
    var role: String
    var company: String
    var avatarSystemName: String
    var lastSharedDate: Date
    var cardLabel: String
    
    // Contact annotations
    var notes: String
    var tags: String  // Comma-separated tags
    var followUpDate: Date?
    var email: String  // Legacy single email (kept for migration/fallback)
    var phone: String  // Legacy single phone (kept for migration/fallback)
    
    // Multiple contact fields (phones, emails, links with labels)
    @Relationship(deleteRule: .cascade, inverse: \ContactField.contact)
    var contactFields: [ContactField]?
    
    // If this is a received card (scanned from someone else)
    var isReceivedCard: Bool
    
    // Profile photo
    @Attribute(.externalStorage) var photoData: Data?

    init(
        id: UUID = UUID(),
        name: String = "",
        role: String = "",
        company: String = "",
        avatarSystemName: String = "person.crop.circle",
        lastSharedDate: Date = .now,
        cardLabel: String = "Work",
        notes: String = "",
        tags: String = "",
        followUpDate: Date? = nil,
        email: String = "",
        phone: String = "",
        isReceivedCard: Bool = false,
        photoData: Data? = nil
    ) {
        self.id = id
        self.name = name
        self.role = role
        self.company = company
        self.avatarSystemName = avatarSystemName
        self.lastSharedDate = lastSharedDate
        self.cardLabel = cardLabel
        self.notes = notes
        self.tags = tags
        self.followUpDate = followUpDate
        self.email = email
        self.phone = phone
        self.isReceivedCard = isReceivedCard
        self.photoData = photoData
    }
    
    /// Returns tags as an array
    var tagList: [String] {
        tags.split(separator: ",")
            .map { $0.trimmingCharacters(in: .whitespaces) }
            .filter { !$0.isEmpty }
    }
    
    /// Returns contact fields sorted by order index
    var sortedContactFields: [ContactField] {
        (contactFields ?? []).sorted { $0.orderIndex < $1.orderIndex }
    }
    
    /// Filters contact fields by type ID
    func fields(ofType typeId: String) -> [ContactField] {
        sortedContactFields.filter { $0.typeId == typeId }
    }
    
    /// Gets all phone numbers
    var phoneNumbers: [ContactField] {
        fields(ofType: "phone")
    }
    
    /// Gets all email addresses
    var emailAddresses: [ContactField] {
        fields(ofType: "email")
    }
    
    /// Gets all links (website + custom links)
    var links: [ContactField] {
        sortedContactFields.filter { $0.typeId == "website" || $0.typeId == "customLink" }
    }
    
    /// Gets all address fields
    var addresses: [ContactField] {
        fields(ofType: "address")
    }
    
    /// Whether this contact has a follow-up reminder set
    var hasFollowUp: Bool {
        followUpDate != nil
    }
    
    /// Whether the follow-up is overdue
    var isFollowUpOverdue: Bool {
        guard let followUpDate else { return false }
        return followUpDate < .now
    }
}

extension Contact {
    static func createSamples(in context: ModelContext) {
        let samples = [
            Contact(
                name: "Kevin Lennox",
                role: "Branch Manager",
                company: "Global Bank",
                avatarSystemName: "person.crop.circle",
                lastSharedDate: .now.addingTimeInterval(-86400 * 14),
                cardLabel: "Work",
                notes: "Met at the Austin fintech conference. Interested in property financing.",
                tags: "finance, potential client",
                followUpDate: .now.addingTimeInterval(86400 * 7),
                email: "kevin.lennox@globalbank.com"
            ),
            Contact(
                name: "Jenny Wright",
                role: "UX Designer",
                company: "App Foundry",
                avatarSystemName: "person.crop.circle.fill",
                lastSharedDate: .now.addingTimeInterval(-86400 * 45),
                cardLabel: "Creative",
                notes: "Great portfolio. Could be a good hire or contractor.",
                tags: "designer, talent",
                email: "jenny@appfoundry.io"
            ),
            Contact(
                name: "Pip McDowell",
                role: "Creative Director",
                company: "Future Noise",
                avatarSystemName: "person.crop.square",
                lastSharedDate: .now.addingTimeInterval(-86400 * 2),
                cardLabel: "Creative",
                notes: "Working on a brand refresh. Follow up next quarter.",
                tags: "agency, branding"
            ),
            Contact(
                name: "Ron James",
                role: "CEO",
                company: "CloudSwitch",
                avatarSystemName: "person.circle",
                lastSharedDate: .now.addingTimeInterval(-86400 * 90),
                cardLabel: "Work",
                notes: "Introduced by Maya. Looking for office space.",
                tags: "VIP, real estate",
                phone: "+1 (555) 987-6543"
            ),
            Contact(
                name: "Alex Lindsey",
                role: "Editor",
                company: "Post Media Studios",
                avatarSystemName: "person.crop.circle",
                lastSharedDate: .now.addingTimeInterval(-86400 * 7),
                cardLabel: "Press",
                notes: "Writing a piece on commercial real estate trends.",
                tags: "press, media"
            )
        ]

        for sample in samples {
            context.insert(sample)
        }
    }
    
    /// Creates a contact from received vCard data
    @MainActor
    static func fromVCard(_ vCardData: String) -> Contact {
        let contact = Contact(isReceivedCard: true)
        contact.contactFields = []
        var fieldIndex = 0
        
        // Parse vCard fields
        let lines = vCardData.components(separatedBy: "\n")
        for line in lines {
            if line.hasPrefix("FN:") {
                contact.name = String(line.dropFirst(3))
            } else if line.hasPrefix("ORG:") {
                contact.company = String(line.dropFirst(4))
            } else if line.hasPrefix("TITLE:") {
                contact.role = String(line.dropFirst(6))
            } else if line.contains("EMAIL") && line.contains(":") {
                if let colonIndex = line.firstIndex(of: ":") {
                    let emailValue = String(line[line.index(after: colonIndex)...])
                    let typeLabel = extractVCardTypeLabel(from: line) ?? "Work"
                    
                    let field = ContactField(typeId: "email", value: emailValue, title: typeLabel, orderIndex: fieldIndex)
                    field.contact = contact
                    contact.contactFields?.append(field)
                    fieldIndex += 1
                    
                    // Also set legacy field for backward compatibility
                    if contact.email.isEmpty {
                        contact.email = emailValue
                    }
                }
            } else if line.contains("TEL") && line.contains(":") {
                if let colonIndex = line.firstIndex(of: ":") {
                    let phoneValue = String(line[line.index(after: colonIndex)...])
                    let typeLabel = extractVCardTypeLabel(from: line) ?? "Cell"
                    
                    let field = ContactField(typeId: "phone", value: phoneValue, title: typeLabel, orderIndex: fieldIndex)
                    field.contact = contact
                    contact.contactFields?.append(field)
                    fieldIndex += 1
                    
                    // Also set legacy field for backward compatibility
                    if contact.phone.isEmpty {
                        contact.phone = phoneValue
                    }
                }
            } else if line.contains("ADR") && line.contains(":") {
                // Parse VCard ADR format: ADR;TYPE=type:;;street;city;state;zip;country
                if let colonIndex = line.firstIndex(of: ":") {
                    let addressPart = String(line[line.index(after: colonIndex)...])
                    let typeLabel = extractVCardTypeLabel(from: line) ?? "Work"
                    
                    let postalAddress = parseVCardADR(addressPart)
                    if postalAddress.hasValue {
                        let field = ContactField(typeId: "address", value: postalAddress.encode(), title: typeLabel, orderIndex: fieldIndex)
                        field.contact = contact
                        contact.contactFields?.append(field)
                        fieldIndex += 1
                    }
                }
            }
        }
        
        contact.lastSharedDate = .now
        contact.cardLabel = "Received"
        return contact
    }
    
    /// Extracts TYPE label from VCard line (e.g., "TYPE=WORK" -> "Work")
    private static func extractVCardTypeLabel(from line: String) -> String? {
        // Look for TYPE= in the line
        guard let typeRange = line.range(of: "TYPE=", options: .caseInsensitive) else {
            return nil
        }
        
        let afterType = line[typeRange.upperBound...]
        // Find end of type value (either ; or :)
        let endIndex = afterType.firstIndex(where: { $0 == ";" || $0 == ":" }) ?? afterType.endIndex
        let typeValue = String(afterType[..<endIndex])
        
        // Capitalize first letter only
        return typeValue.capitalized
    }
    
    /// Parses VCard ADR format into PostalAddress
    /// Format: ;;street;city;state;postalCode;country (PO Box and Extended are typically empty)
    private static func parseVCardADR(_ adrValue: String) -> PostalAddress {
        let components = adrValue.split(separator: ";", omittingEmptySubsequences: false).map { String($0) }
        
        var address = PostalAddress()
        
        // VCard ADR format: PO Box; Extended; Street; City; State; Postal Code; Country
        // Index:              0        1        2       3      4        5           6
        if components.count > 2 {
            address.street = components[2].trimmingCharacters(in: .whitespaces)
        }
        if components.count > 3 {
            address.city = components[3].trimmingCharacters(in: .whitespaces)
        }
        if components.count > 4 {
            address.state = components[4].trimmingCharacters(in: .whitespaces)
        }
        if components.count > 5 {
            address.postalCode = components[5].trimmingCharacters(in: .whitespaces)
        }
        if components.count > 6 {
            address.country = components[6].trimmingCharacters(in: .whitespaces)
        }
        
        return address
    }
}
