lib/attio/resources/company.rb



# frozen_string_literal: true

require_relative "typed_record"

module Attio
  # Represents a company record in Attio
  # Provides convenient methods for working with companies and their attributes
  class Company < TypedRecord
    object_type "companies"

    # Set the company name (much simpler than person names!)
    # @param name [String] The company name
    def name=(name)
      self[:name] = name
    end

    # Get the company name
    # @return [String, nil] The company name or nil if not set
    def name
      self[:name]
    end

    # Add a domain
    # @param domain [String] The domain to add (e.g., "example.com")
    def add_domain(domain)
      domains = self[:domains] || []
      # Ensure it's an array
      domains = [domains] unless domains.is_a?(Array)

      # Normalize domain (remove protocol if present)
      domain = domain.sub(/^https?:\/\//, "")

      # Check if domain already exists
      exists = domains.any? { |d|
        d.is_a?(Hash) ? (d["domain"] == domain || d[:domain] == domain) : d == domain
      }

      unless exists
        # Extract just the domain strings if we have hashes
        domain_strings = domains.filter_map { |d|
          d.is_a?(Hash) ? (d["domain"] || d[:domain]) : d
        }

        # Add the new domain
        domain_strings << domain

        # Set as simple array of strings
        self[:domains] = domain_strings
      end
    end

    # Get the primary domain
    # @return [String, nil] The primary domain or nil if not set
    def domain
      domains = self[:domains]
      return nil unless domains

      extract_primary_value(domains, "domain")
    end

    # Get all domains
    # @return [Array<String>] Array of domain strings
    def domains_list
      domains = self[:domains]
      return [] unless domains

      case domains
      when Array
        domains.filter_map { |d| extract_field_value(d, "domain") }
      else
        [domain].compact
      end
    end

    private

    # Extract primary value from various data structures
    # @param value [Array, Hash, Object] The value to extract from
    # @param field [String] The field name for hash extraction
    # @return [String, nil] The extracted value
    def extract_primary_value(value, field)
      case value
      when Array
        return nil if value.empty?
        extract_field_value(value.first, field)
      when Hash
        value[field] || value[field.to_sym]
      else
        value.to_s
      end
    end

    # Extract a value from a hash or convert to string
    # @param item [Hash, Object] The item to extract from
    # @param field [String] The field name for hash extraction
    # @return [String] The extracted value
    def extract_field_value(item, field)
      case item
      when Hash
        item[field] || item[field.to_sym]
      else
        item.to_s
      end
    end

    public

    # Set the company description
    # @param description [String] The company description
    def description=(desc)
      self[:description] = desc
    end

    # Set the employee count
    # @param count [Integer, String] The employee count or range (e.g., "10-50")
    def employee_count=(count)
      self[:employee_count] = count.to_s
    end

    # Add a team member (person) to this company
    # @param person [Person, String] A Person instance or person ID
    def add_team_member(person)
      # This would typically be done from the Person side
      # but we can provide a convenience method
      if person.is_a?(Person)
        person.company = self
        person.save
      elsif person.is_a?(String)
        # If it's an ID, we need to fetch and update the person
        retrieved_person = Person.retrieve(person)
        retrieved_person.company = self
        retrieved_person.save
      else
        raise ArgumentError, "Team member must be a Person instance or ID string"
      end
    end

    # Get all people associated with this company
    # @return [Attio::ListObject] List of people
    def team_members(**opts)
      company_id = id.is_a?(Hash) ? id["record_id"] : id
      Person.list(**opts.merge(params: {
        filter: {
          company: {
            target_object: "companies",
            target_record_id: company_id
          }
        }
      }))
    end

    class << self
      # Create a company with a simplified interface
      # @param attributes [Hash] Company attributes
      # @option attributes [String] :name Company name (required)
      # @option attributes [String, Array<String>] :domain Domain(s)
      # @option attributes [String] :description Company description
      # @option attributes [String, Integer] :employee_count Employee count
      # @option attributes [Hash] :values Raw values hash (for advanced use)
      def create(name:, domain: nil, domains: nil, description: nil,
        employee_count: nil, values: {}, **opts)
        # Name is required and simple for companies
        values[:name] = name

        # Handle domains
        if domain || domains
          domain_list = []
          domain_list << domain if domain
          domain_list += Array(domains) if domains
          values[:domains] = domain_list.uniq unless domain_list.empty?
        end

        values[:description] = description if description
        values[:employee_count] = employee_count.to_s if employee_count

        super(values: values, **opts)
      end


      # Find companies by employee count range
      # @param min [Integer] Minimum employee count
      # @param max [Integer] Maximum employee count (optional)
      def find_by_size(min, max = nil, **opts)
        filter = if max
          {
            employee_count: {
              "$gte": min.to_s,
              "$lte": max.to_s
            }
          }
        else
          {
            employee_count: {"$gte": min.to_s}
          }
        end

        list(**opts.merge(params: {filter: filter}))
      end
      
      private
      
      # Build filter for domain field
      def filter_by_domain(value)
        # Strip protocol if present
        normalized_domain = value.sub(/^https?:\/\//, "")
        {
          domains: {
            domain: {
              "$eq": normalized_domain
            }
          }
        }
      end
      
      # Build filter for name field
      def filter_by_name(value)
        {
          name: {"$contains": value}
        }
      end
    end
  end

  # Convenience alias
  Companies = Company
end