package com.social.media.domain.entity;

import jakarta.persistence.*;
import jakarta.validation.constraints.*;

import java.time.LocalDateTime;
import java.util.Objects;

@Entity
@Table(name = "companies", schema = "core_business",
       uniqueConstraints = {
           @UniqueConstraint(name = "companies_cnpj_key", columnNames = {"cnpj"}),
           @UniqueConstraint(name = "companies_company_code_key", columnNames = {"company_code"}),
           @UniqueConstraint(name = "companies_email_key", columnNames = {"email"}),
           @UniqueConstraint(name = "uq_companies_branch_code_per_parent", 
                           columnNames = {"parent_company_id", "branch_code"})
       })
public class Company {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    
    @Column(name = "company_code", nullable = false, length = 20)
    private String companyCode;
    
    @NotBlank(message = "Nome é obrigatório")
    @Size(max = 200, message = "Nome deve ter no máximo 200 caracteres")
    @Column(name = "name", nullable = false, length = 200)
    private String name;
    
    @NotBlank(message = "Email é obrigatório")
    @Email(message = "Email deve ter formato válido")
    @Size(max = 100, message = "Email deve ter no máximo 100 caracteres")
    @Column(name = "email", nullable = false, length = 100)
    private String email;
    
    @NotBlank(message = "CNPJ é obrigatório")
    @Pattern(regexp = "^\\d{2}\\.\\d{3}\\.\\d{3}/\\d{4}-\\d{2}$", message = "CNPJ deve ter formato válido (XX.XXX.XXX/XXXX-XX)")
    @Column(name = "cnpj", nullable = false, length = 18)
    private String cnpj;
    
    @Size(max = 20, message = "Telefone deve ter no máximo 20 caracteres")
    @Column(name = "phone", length = 20)
    private String phone;
    
    @Size(max = 255, message = "Website deve ter no máximo 255 caracteres")
    @Column(name = "website", length = 255)
    private String website;
    
    @Size(max = 100, message = "Setor de atividade deve ter no máximo 100 caracteres")
    @Column(name = "activity_sector", length = 100)
    private String activitySector;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "plan", nullable = false)
    private CompanyPlan plan = CompanyPlan.BASIC;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false)
    private CompanyStatus status = CompanyStatus.TRIAL;
    
    // Address fields
    @Size(max = 200, message = "Rua deve ter no máximo 200 caracteres")
    @Column(name = "address_street", length = 200)
    private String addressStreet;
    
    @Size(max = 20, message = "Número deve ter no máximo 20 caracteres")
    @Column(name = "address_number", length = 20)
    private String addressNumber;
    
    @Size(max = 100, message = "Complemento deve ter no máximo 100 caracteres")
    @Column(name = "address_complement", length = 100)
    private String addressComplement;
    
    @Size(max = 100, message = "Bairro deve ter no máximo 100 caracteres")
    @Column(name = "address_neighborhood", length = 100)
    private String addressNeighborhood;
    
    @Size(max = 100, message = "Cidade deve ter no máximo 100 caracteres")
    @Column(name = "address_city", length = 100)
    private String addressCity;
    
    @Size(max = 50, message = "Estado deve ter no máximo 50 caracteres")
    @Column(name = "address_state", length = 50)
    private String addressState;
    
    @Size(max = 10, message = "CEP deve ter no máximo 10 caracteres")
    @Column(name = "address_zip_code", length = 10)
    private String addressZipCode;
    
    @Size(max = 50, message = "País deve ter no máximo 50 caracteres")
    @Column(name = "address_country", length = 50)
    private String addressCountry;
    
    // Hierarchy fields
    @Column(name = "parent_company_id")
    private Long parentCompanyId;
    
    @Min(value = 0, message = "Nível hierárquico deve ser no mínimo 0")
    @Max(value = 5, message = "Nível hierárquico deve ser no máximo 5")
    @Column(name = "hierarchy_level", nullable = false)
    private Integer hierarchyLevel = 0;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "branch_type", nullable = false)
    private CompanyBranchType branchType = CompanyBranchType.MATRIZ;
    
    @Pattern(regexp = "^[A-Z0-9]{3,10}$", message = "Código da filial deve ter formato válido (3-10 caracteres alfanuméricos maiúsculos)")
    @Column(name = "branch_code", length = 10)
    private String branchCode;
    
    @Size(max = 100, message = "Região deve ter no máximo 100 caracteres")
    @Column(name = "region", length = 100)
    private String region;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "branch_status", nullable = false)
    private CompanyBranchStatus branchStatus = CompanyBranchStatus.ACTIVE;
    
    // Audit fields
    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;
    
    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;
    
    @Column(name = "created_by")
    private Long createdBy;
    
    @Column(name = "updated_by")
    private Long updatedBy;
    
    @Column(name = "version")
    private Long version = 1L;
    
    // Enums
    public enum CompanyPlan {
        BASIC, PREMIUM, ENTERPRISE
    }
    
    public enum CompanyStatus {
        TRIAL, ACTIVE, INACTIVE, SUSPENDED, CANCELLED
    }
    
    public enum CompanyBranchType {
        MATRIZ, FILIAL, SUCURSAL, FRANQUIA, REPRESENTACAO
    }
    
    public enum CompanyBranchStatus {
        ACTIVE, INACTIVE, SUSPENDED, CLOSED
    }
    
    // Constructors
    public Company() {
    }
    
    public Company(String name, String email, String cnpj) {
        this.name = name;
        this.email = email;
        this.cnpj = cnpj;
        this.createdAt = LocalDateTime.now();
        this.updatedAt = LocalDateTime.now();
    }
    
    public Company(String name, String email, String cnpj, String phone, String website) {
        this.name = name;
        this.email = email;
        this.cnpj = cnpj;
        this.phone = phone;
        this.website = website;
        this.createdAt = LocalDateTime.now();
        this.updatedAt = LocalDateTime.now();
    }
    
    // Lifecycle callbacks
    @PrePersist
    protected void onCreate() {
        LocalDateTime now = LocalDateTime.now();
        if (createdAt == null) {
            createdAt = now;
        }
        updatedAt = now;
        
        // Set default values if not provided
        if (plan == null) {
            plan = CompanyPlan.BASIC;
        }
        if (status == null) {
            status = CompanyStatus.TRIAL;
        }
        if (hierarchyLevel == null) {
            hierarchyLevel = 0;
        }
        if (branchType == null) {
            branchType = CompanyBranchType.MATRIZ;
        }
        if (branchStatus == null) {
            branchStatus = CompanyBranchStatus.ACTIVE;
        }
        if (version == null) {
            version = 1L;
        }
    }
    
    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
    }
    
    // Getters and Setters
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getCompanyCode() {
        return companyCode;
    }
    
    public void setCompanyCode(String companyCode) {
        this.companyCode = companyCode;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getEmail() {
        return email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    public String getCnpj() {
        return cnpj;
    }
    
    public void setCnpj(String cnpj) {
        this.cnpj = cnpj;
    }
    
    public String getPhone() {
        return phone;
    }
    
    public void setPhone(String phone) {
        this.phone = phone;
    }
    
    public String getWebsite() {
        return website;
    }
    
    public void setWebsite(String website) {
        this.website = website;
    }
    
    public String getActivitySector() {
        return activitySector;
    }
    
    public void setActivitySector(String activitySector) {
        this.activitySector = activitySector;
    }
    
    public CompanyPlan getPlan() {
        return plan;
    }
    
    public void setPlan(CompanyPlan plan) {
        this.plan = plan;
    }
    
    public CompanyStatus getStatus() {
        return status;
    }
    
    public void setStatus(CompanyStatus status) {
        this.status = status;
    }
    
    public String getAddressStreet() {
        return addressStreet;
    }
    
    public void setAddressStreet(String addressStreet) {
        this.addressStreet = addressStreet;
    }
    
    public String getAddressNumber() {
        return addressNumber;
    }
    
    public void setAddressNumber(String addressNumber) {
        this.addressNumber = addressNumber;
    }
    
    public String getAddressComplement() {
        return addressComplement;
    }
    
    public void setAddressComplement(String addressComplement) {
        this.addressComplement = addressComplement;
    }
    
    public String getAddressNeighborhood() {
        return addressNeighborhood;
    }
    
    public void setAddressNeighborhood(String addressNeighborhood) {
        this.addressNeighborhood = addressNeighborhood;
    }
    
    public String getAddressCity() {
        return addressCity;
    }
    
    public void setAddressCity(String addressCity) {
        this.addressCity = addressCity;
    }
    
    public String getAddressState() {
        return addressState;
    }
    
    public void setAddressState(String addressState) {
        this.addressState = addressState;
    }
    
    public String getAddressZipCode() {
        return addressZipCode;
    }
    
    public void setAddressZipCode(String addressZipCode) {
        this.addressZipCode = addressZipCode;
    }
    
    public String getAddressCountry() {
        return addressCountry;
    }
    
    public void setAddressCountry(String addressCountry) {
        this.addressCountry = addressCountry;
    }
    
    public Long getParentCompanyId() {
        return parentCompanyId;
    }
    
    public void setParentCompanyId(Long parentCompanyId) {
        this.parentCompanyId = parentCompanyId;
    }
    
    public Integer getHierarchyLevel() {
        return hierarchyLevel;
    }
    
    public void setHierarchyLevel(Integer hierarchyLevel) {
        this.hierarchyLevel = hierarchyLevel;
    }
    
    public CompanyBranchType getBranchType() {
        return branchType;
    }
    
    public void setBranchType(CompanyBranchType branchType) {
        this.branchType = branchType;
    }
    
    public String getBranchCode() {
        return branchCode;
    }
    
    public void setBranchCode(String branchCode) {
        this.branchCode = branchCode;
    }
    
    public String getRegion() {
        return region;
    }
    
    public void setRegion(String region) {
        this.region = region;
    }
    
    public CompanyBranchStatus getBranchStatus() {
        return branchStatus;
    }
    
    public void setBranchStatus(CompanyBranchStatus branchStatus) {
        this.branchStatus = branchStatus;
    }
    
    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;
    }
    
    public Long getCreatedBy() {
        return createdBy;
    }
    
    public void setCreatedBy(Long createdBy) {
        this.createdBy = createdBy;
    }
    
    public Long getUpdatedBy() {
        return updatedBy;
    }
    
    public void setUpdatedBy(Long updatedBy) {
        this.updatedBy = updatedBy;
    }
    
    public Long getVersion() {
        return version;
    }
    
    public void setVersion(Long version) {
        this.version = version;
    }
    
    // Business methods
    public boolean isActive() {
        return status == CompanyStatus.ACTIVE;
    }
    
    public boolean isMatriz() {
        return branchType == CompanyBranchType.MATRIZ;
    }
    
    public boolean hasParentCompany() {
        return parentCompanyId != null;
    }
    
    public String getFullAddress() {
        StringBuilder address = new StringBuilder();
        if (addressStreet != null) {
            address.append(addressStreet);
            if (addressNumber != null) {
                address.append(", ").append(addressNumber);
            }
            if (addressComplement != null) {
                address.append(", ").append(addressComplement);
            }
            if (addressNeighborhood != null) {
                address.append(", ").append(addressNeighborhood);
            }
            if (addressCity != null) {
                address.append(", ").append(addressCity);
            }
            if (addressState != null) {
                address.append(" - ").append(addressState);
            }
            if (addressZipCode != null) {
                address.append(" CEP: ").append(addressZipCode);
            }
        }
        return address.toString();
    }
    
    // equals and hashCode
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Company company = (Company) o;
        return Objects.equals(id, company.id) && Objects.equals(cnpj, company.cnpj);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id, cnpj);
    }
    
    @Override
    public String toString() {
        return "Company{" +
                "id=" + id +
                ", companyCode='" + companyCode + '\'' +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", cnpj='" + cnpj + '\'' +
                ", plan=" + plan +
                ", status=" + status +
                ", branchType=" + branchType +
                '}';
    }
}
