package com.social.media.domain.entity;

import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;

@Entity
@Table(name = "social_accounts", schema = "core_business",
       uniqueConstraints = {
           @UniqueConstraint(name = "social_accounts_account_code_key", columnNames = {"account_code"}),
           @UniqueConstraint(name = "chk_social_accounts_company_network_username_unique", 
                           columnNames = {"company_id", "social_network_id", "username"})
       },
       indexes = {
           @Index(name = "idx_social_accounts_active", columnList = "active"),
           @Index(name = "idx_social_accounts_company_id", columnList = "company_id"),
           @Index(name = "idx_social_accounts_connection_status", columnList = "connection_status"),
           @Index(name = "idx_social_accounts_deleted", columnList = "deleted"),
           @Index(name = "idx_social_accounts_last_sync_date", columnList = "last_sync_date"),
           @Index(name = "idx_social_accounts_responsible_user_id", columnList = "responsible_user_id"),
           @Index(name = "idx_social_accounts_social_network_id", columnList = "social_network_id"),
           @Index(name = "idx_social_accounts_username", columnList = "username")
       })
public class SocialAccount {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "account_code", nullable = false, unique = true, length = 20)
    private String accountCode;
    
    @NotNull(message = "Company ID é obrigatório")
    @Column(name = "company_id", nullable = false)
    private Long companyId;
    
    @NotNull(message = "Social Network ID é obrigatório")
    @Column(name = "social_network_id", nullable = false)
    private Long socialNetworkId;
    
    @Column(name = "responsible_user_id")
    private Long responsibleUserId;
    
    @NotBlank(message = "Username é obrigatório")
    @Size(max = 100, message = "Username deve ter no máximo 100 caracteres")
    @Pattern(regexp = "^\\S+$", message = "Username não pode conter espaços em branco")
    @Column(name = "username", nullable = false, length = 100)
    private String username;
    
    @Size(max = 255, message = "Display name deve ter no máximo 255 caracteres")
    @Column(name = "display_name", length = 255)
    private String displayName;
    
    @Column(name = "bio", columnDefinition = "TEXT")
    private String bio;
    
    @Size(max = 1000, message = "URL da foto do perfil deve ter no máximo 1000 caracteres")
    @Column(name = "profile_photo_url", length = 1000)
    private String profilePhotoUrl;
    
    @Size(max = 1000, message = "URL do perfil deve ter no máximo 1000 caracteres")
    @Column(name = "profile_url", length = 1000)
    private String profileUrl;
    
    @Column(name = "verified", nullable = false)
    private Boolean verified = false;
    
    @Column(name = "is_private", nullable = false)
    private Boolean isPrivate = false;
    
    @Size(max = 100, message = "Categoria deve ter no máximo 100 caracteres")
    @Column(name = "category", length = 100)
    private String category;
    
    @Size(max = 20, message = "Telefone de contato deve ter no máximo 20 caracteres")
    @Column(name = "contact_phone", length = 20)
    private String contactPhone;
    
    @Email(message = "Email de contato deve ser válido")
    @Size(max = 320, message = "Email de contato deve ter no máximo 320 caracteres")
    @Column(name = "contact_email", length = 320)
    private String contactEmail;
    
    @Size(max = 255, message = "Localização deve ter no máximo 255 caracteres")
    @Column(name = "location", length = 255)
    private String location;
    
    @Size(max = 500, message = "Website deve ter no máximo 500 caracteres")
    @Column(name = "website", length = 500)
    private String website;
    
    @JdbcTypeCode(SqlTypes.JSON)
    @Column(name = "metrics", columnDefinition = "jsonb")
    private Map<String, Object> metrics;
    
    @Size(max = 50, message = "Tipo de conta deve ter no máximo 50 caracteres")
    @Column(name = "account_type", length = 50)
    private String accountType = "PERSONAL";
    
    @Size(max = 100, message = "Categoria de negócio deve ter no máximo 100 caracteres")
    @Column(name = "business_category", length = 100)
    private String businessCategory;
    
    @Min(value = 0, message = "Meta de seguidores deve ser no mínimo 0")
    @Column(name = "follower_target")
    private Integer followerTarget;
    
    @DecimalMin(value = "0.0", message = "Meta de engajamento deve ser no mínimo 0.0")
    @DecimalMax(value = "100.0", message = "Meta de engajamento deve ser no máximo 100.0")
    @Column(name = "engagement_target", precision = 5, scale = 2)
    private BigDecimal engagementTarget;
    
    @Column(name = "last_metrics_update")
    private LocalDateTime lastMetricsUpdate;
    
    @NotNull(message = "Status de conexão é obrigatório")
    @Enumerated(EnumType.STRING)
    @Column(name = "connection_status", nullable = false)
    private ConnectionStatus connectionStatus = ConnectionStatus.PENDING;
    
    @Column(name = "last_sync_date")
    private LocalDateTime lastSyncDate;
    
    @Column(name = "next_sync_date")
    private LocalDateTime nextSyncDate;
    
    @Column(name = "last_sync_error", columnDefinition = "TEXT")
    private String lastSyncError;
    
    @Column(name = "active", nullable = false)
    private Boolean active = true;
    
    @Column(name = "registration_date", nullable = false)
    private LocalDateTime registrationDate;
    
    @Column(name = "last_update_date", nullable = false)
    private LocalDateTime lastUpdateDate;
    
    @Column(name = "deleted", nullable = false)
    private Boolean deleted = false;
    
    @Column(name = "created_at", nullable = false)
    private LocalDateTime createdAt;
    
    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;
    
    // Enums
    public enum ConnectionStatus {
        PENDING, CONNECTING, CONNECTED, DISCONNECTED, ERROR, EXPIRED
    }
    
    public enum AccountType {
        PERSONAL, BUSINESS, CREATOR, BRAND
    }
    
    // Constructors
    public SocialAccount() {}
    
    public SocialAccount(Long companyId, Long socialNetworkId, String username) {
        this.companyId = companyId;
        this.socialNetworkId = socialNetworkId;
        this.username = username;
        this.registrationDate = LocalDateTime.now();
        this.lastUpdateDate = LocalDateTime.now();
        this.createdAt = LocalDateTime.now();
        this.updatedAt = LocalDateTime.now();
    }
    
    public SocialAccount(Long companyId, Long socialNetworkId, String username, String displayName) {
        this(companyId, socialNetworkId, username);
        this.displayName = displayName;
    }
    
    // Lifecycle callbacks
    @PrePersist
    protected void onCreate() {
        LocalDateTime now = LocalDateTime.now();
        if (createdAt == null) {
            createdAt = now;
        }
        if (registrationDate == null) {
            registrationDate = now;
        }
        updatedAt = now;
        lastUpdateDate = now;
        
        // Set default values if not provided
        if (connectionStatus == null) {
            connectionStatus = ConnectionStatus.PENDING;
        }
        if (active == null) {
            active = true;
        }
        if (deleted == null) {
            deleted = false;
        }
        if (verified == null) {
            verified = false;
        }
        if (isPrivate == null) {
            isPrivate = false;
        }
        if (accountType == null) {
            accountType = "PERSONAL";
        }
        
        // Initialize metrics if null
        if (metrics == null) {
            metrics = Map.of(
                "posts", 0,
                "followers", 0,
                "following", 0,
                "engagement", 0.0
            );
        }
    }
    
    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
        lastUpdateDate = LocalDateTime.now();
    }
    
    // Business methods
    public void connect() {
        this.connectionStatus = ConnectionStatus.CONNECTED;
        this.lastSyncDate = LocalDateTime.now();
        this.lastSyncError = null;
    }
    
    public void disconnect() {
        this.connectionStatus = ConnectionStatus.DISCONNECTED;
    }
    
    public void setConnectionError(String error) {
        this.connectionStatus = ConnectionStatus.ERROR;
        this.lastSyncError = error;
    }
    
    public void activate() {
        this.active = true;
    }
    
    public void deactivate() {
        this.active = false;
    }
    
    public void softDelete() {
        this.deleted = true;
        this.active = false;
    }
    
    public void updateMetrics(Map<String, Object> newMetrics) {
        this.metrics = newMetrics;
        this.lastMetricsUpdate = LocalDateTime.now();
    }
    
    public void updateMetrics(Integer posts, Integer followers, Integer following, Double engagement) {
        this.metrics = Map.of(
            "posts", posts != null ? posts : 0,
            "followers", followers != null ? followers : 0,
            "following", following != null ? following : 0,
            "engagement", engagement != null ? engagement : 0.0
        );
        this.lastMetricsUpdate = LocalDateTime.now();
    }
    
    public void scheduleNextSync(LocalDateTime nextSync) {
        this.nextSyncDate = nextSync;
    }
    
    public boolean isConnected() {
        return connectionStatus == ConnectionStatus.CONNECTED;
    }
    
    public boolean isActive() {
        return active && !deleted;
    }
    
    public boolean needsSync() {
        return nextSyncDate != null && nextSyncDate.isBefore(LocalDateTime.now());
    }
    
    public Integer getFollowersCount() {
        if (metrics != null && metrics.containsKey("followers")) {
            Object followers = metrics.get("followers");
            if (followers instanceof Integer) {
                return (Integer) followers;
            } else if (followers instanceof Number) {
                return ((Number) followers).intValue();
            }
        }
        return 0;
    }
    
    public Integer getFollowingCount() {
        if (metrics != null && metrics.containsKey("following")) {
            Object following = metrics.get("following");
            if (following instanceof Integer) {
                return (Integer) following;
            } else if (following instanceof Number) {
                return ((Number) following).intValue();
            }
        }
        return 0;
    }
    
    public Integer getPostsCount() {
        if (metrics != null && metrics.containsKey("posts")) {
            Object posts = metrics.get("posts");
            if (posts instanceof Integer) {
                return (Integer) posts;
            } else if (posts instanceof Number) {
                return ((Number) posts).intValue();
            }
        }
        return 0;
    }
    
    public Double getEngagementRate() {
        if (metrics != null && metrics.containsKey("engagement")) {
            Object engagement = metrics.get("engagement");
            if (engagement instanceof Double) {
                return (Double) engagement;
            } else if (engagement instanceof Number) {
                return ((Number) engagement).doubleValue();
            }
        }
        return 0.0;
    }
    
    // Getters and Setters
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getAccountCode() {
        return accountCode;
    }
    
    public void setAccountCode(String accountCode) {
        this.accountCode = accountCode;
    }
    
    public Long getCompanyId() {
        return companyId;
    }
    
    public void setCompanyId(Long companyId) {
        this.companyId = companyId;
    }
    
    public Long getSocialNetworkId() {
        return socialNetworkId;
    }
    
    public void setSocialNetworkId(Long socialNetworkId) {
        this.socialNetworkId = socialNetworkId;
    }
    
    public Long getResponsibleUserId() {
        return responsibleUserId;
    }
    
    public void setResponsibleUserId(Long responsibleUserId) {
        this.responsibleUserId = responsibleUserId;
    }
    
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getDisplayName() {
        return displayName;
    }
    
    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }
    
    public String getBio() {
        return bio;
    }
    
    public void setBio(String bio) {
        this.bio = bio;
    }
    
    public String getProfilePhotoUrl() {
        return profilePhotoUrl;
    }
    
    public void setProfilePhotoUrl(String profilePhotoUrl) {
        this.profilePhotoUrl = profilePhotoUrl;
    }
    
    public String getProfileUrl() {
        return profileUrl;
    }
    
    public void setProfileUrl(String profileUrl) {
        this.profileUrl = profileUrl;
    }
    
    public Boolean getVerified() {
        return verified;
    }
    
    public void setVerified(Boolean verified) {
        this.verified = verified;
    }
    
    public Boolean getIsPrivate() {
        return isPrivate;
    }
    
    public void setIsPrivate(Boolean isPrivate) {
        this.isPrivate = isPrivate;
    }
    
    public String getCategory() {
        return category;
    }
    
    public void setCategory(String category) {
        this.category = category;
    }
    
    public String getContactPhone() {
        return contactPhone;
    }
    
    public void setContactPhone(String contactPhone) {
        this.contactPhone = contactPhone;
    }
    
    public String getContactEmail() {
        return contactEmail;
    }
    
    public void setContactEmail(String contactEmail) {
        this.contactEmail = contactEmail;
    }
    
    public String getLocation() {
        return location;
    }
    
    public void setLocation(String location) {
        this.location = location;
    }
    
    public String getWebsite() {
        return website;
    }
    
    public void setWebsite(String website) {
        this.website = website;
    }
    
    public Map<String, Object> getMetrics() {
        return metrics;
    }
    
    public void setMetrics(Map<String, Object> metrics) {
        this.metrics = metrics;
    }
    
    public String getAccountType() {
        return accountType;
    }
    
    public void setAccountType(String accountType) {
        this.accountType = accountType;
    }
    
    public String getBusinessCategory() {
        return businessCategory;
    }
    
    public void setBusinessCategory(String businessCategory) {
        this.businessCategory = businessCategory;
    }
    
    public Integer getFollowerTarget() {
        return followerTarget;
    }
    
    public void setFollowerTarget(Integer followerTarget) {
        this.followerTarget = followerTarget;
    }
    
    public BigDecimal getEngagementTarget() {
        return engagementTarget;
    }
    
    public void setEngagementTarget(BigDecimal engagementTarget) {
        this.engagementTarget = engagementTarget;
    }
    
    public LocalDateTime getLastMetricsUpdate() {
        return lastMetricsUpdate;
    }
    
    public void setLastMetricsUpdate(LocalDateTime lastMetricsUpdate) {
        this.lastMetricsUpdate = lastMetricsUpdate;
    }
    
    public ConnectionStatus getConnectionStatus() {
        return connectionStatus;
    }
    
    public void setConnectionStatus(ConnectionStatus connectionStatus) {
        this.connectionStatus = connectionStatus;
    }
    
    public LocalDateTime getLastSyncDate() {
        return lastSyncDate;
    }
    
    public void setLastSyncDate(LocalDateTime lastSyncDate) {
        this.lastSyncDate = lastSyncDate;
    }
    
    public LocalDateTime getNextSyncDate() {
        return nextSyncDate;
    }
    
    public void setNextSyncDate(LocalDateTime nextSyncDate) {
        this.nextSyncDate = nextSyncDate;
    }
    
    public String getLastSyncError() {
        return lastSyncError;
    }
    
    public void setLastSyncError(String lastSyncError) {
        this.lastSyncError = lastSyncError;
    }
    
    public Boolean getActive() {
        return active;
    }
    
    public void setActive(Boolean active) {
        this.active = active;
    }
    
    public LocalDateTime getRegistrationDate() {
        return registrationDate;
    }
    
    public void setRegistrationDate(LocalDateTime registrationDate) {
        this.registrationDate = registrationDate;
    }
    
    public LocalDateTime getLastUpdateDate() {
        return lastUpdateDate;
    }
    
    public void setLastUpdateDate(LocalDateTime lastUpdateDate) {
        this.lastUpdateDate = lastUpdateDate;
    }
    
    public Boolean getDeleted() {
        return deleted;
    }
    
    public void setDeleted(Boolean deleted) {
        this.deleted = deleted;
    }
    
    public LocalDateTime getCreatedAt() {
        return createdAt;
    }
    
    public void setCreatedAt(LocalDateTime createdAt) {
        this.createdAt = createdAt;
    }
    
    public LocalDateTime getUpdatedAt() {
        return updatedAt;
    }
    
    public void setUpdatedAt(LocalDateTime updatedAt) {
        this.updatedAt = updatedAt;
    }
    
    // equals and hashCode
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SocialAccount that = (SocialAccount) o;
        return Objects.equals(id, that.id) && Objects.equals(accountCode, that.accountCode);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id, accountCode);
    }
    
    @Override
    public String toString() {
        return "SocialAccount{" +
                "id=" + id +
                ", accountCode='" + accountCode + '\'' +
                ", companyId=" + companyId +
                ", socialNetworkId=" + socialNetworkId +
                ", username='" + username + '\'' +
                ", displayName='" + displayName + '\'' +
                ", connectionStatus=" + connectionStatus +
                ", active=" + active +
                '}';
    }
}
