package com.social.media.domain.company.valueobjects;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

/**
 * PhoneNumber Value Object
 * 
 * Represents a phone number with validation and formatting
 * capabilities for Brazilian phone numbers.
 * 
 * @author Social Media Manager Team
 * @since 2.0.0
 */
@Embeddable
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode
public class PhoneNumber {
    
    @Column(name = "phone_number", length = 20)
    private String value;
    
    @Column(name = "phone_country_code", length = 5)
    private String countryCode = "+55";
    
    private PhoneNumber(String value, String countryCode) {
        this.value = value;
        this.countryCode = countryCode;
    }
    
    /**
     * Create Brazilian phone number
     */
    @JsonCreator
    public static PhoneNumber of(String phoneNumber) {
        return of(phoneNumber, "+55");
    }
    
    /**
     * Create phone number with country code
     */
    public static PhoneNumber of(String phoneNumber, String countryCode) {
        if (phoneNumber == null || phoneNumber.isBlank()) {
            throw new IllegalArgumentException("Phone number cannot be null or empty");
        }
        
        if (countryCode == null || countryCode.isBlank()) {
            countryCode = "+55";
        }
        
        var cleanPhone = cleanPhoneNumber(phoneNumber);
        
        if (!isValidBrazilianPhone(cleanPhone)) {
            throw new IllegalArgumentException("Invalid phone number: " + phoneNumber);
        }
        
        return new PhoneNumber(formatBrazilianPhone(cleanPhone), countryCode);
    }
    
    /**
     * Get formatted phone number with country code
     */
    @JsonValue
    public String getFullNumber() {
        return countryCode + " " + value;
    }
    
    /**
     * Get phone number without formatting (digits only)
     */
    public String getDigitsOnly() {
        return value != null ? value.replaceAll("[^0-9]", "") : null;
    }
    
    /**
     * Check if it's a mobile number (starts with 9)
     */
    public boolean isMobile() {
        var digits = getDigitsOnly();
        return digits != null && digits.length() == 11 && digits.charAt(2) == '9';
    }
    
    /**
     * Check if it's a landline number
     */
    public boolean isLandline() {
        var digits = getDigitsOnly();
        return digits != null && digits.length() == 10;
    }
    
    /**
     * Clean phone number string (remove all non-digit characters)
     */
    private static String cleanPhoneNumber(String phone) {
        return phone.replaceAll("[^0-9]", "");
    }
    
    /**
     * Format Brazilian phone number
     */
    private static String formatBrazilianPhone(String phone) {
        if (phone.length() == 11) {
            // Mobile: (XX) 9XXXX-XXXX
            return "(" + phone.substring(0, 2) + ") " +
                   phone.substring(2, 7) + "-" +
                   phone.substring(7, 11);
        } else if (phone.length() == 10) {
            // Landline: (XX) XXXX-XXXX
            return "(" + phone.substring(0, 2) + ") " +
                   phone.substring(2, 6) + "-" +
                   phone.substring(6, 10);
        }
        
        return phone;
    }
    
    /**
     * Validate Brazilian phone number
     */
    private static boolean isValidBrazilianPhone(String phone) {
        if (phone == null) {
            return false;
        }
        
        // Must be 10 digits (landline) or 11 digits (mobile)
        if (phone.length() != 10 && phone.length() != 11) {
            return false;
        }
        
        try {
            // Check if all characters are digits
            Long.parseLong(phone);
            
            // Area code must be valid (11-99)
            int areaCode = Integer.parseInt(phone.substring(0, 2));
            if (areaCode < 11 || areaCode > 99) {
                return false;
            }
            
            // If 11 digits, third digit must be 9 (mobile)
            if (phone.length() == 11) {
                return phone.charAt(2) == '9';
            }
            
            // If 10 digits, third digit cannot be 0, 1, or 9
            if (phone.length() == 10) {
                char thirdDigit = phone.charAt(2);
                return thirdDigit != '0' && thirdDigit != '1' && thirdDigit != '9';
            }
            
            return true;
            
        } catch (NumberFormatException e) {
            return false;
        }
    }
    
    @Override
    public String toString() {
        return getFullNumber();
    }
}
