/**
 * Selector class for Account queries.
 * Encapsulates all SOQL for Account records.
 * All methods return bulkified results (Lists or Maps).
 */
public inherited sharing class AccountSelector {

    // ─── Field Lists ─────────────────────────────────────────────────────

    /**
     * Returns the default set of fields to query for Account.
     *              Centralizes field references to keep queries DRY.
     * @return Comma-separated field list as a String
     */
    private static String getDefaultFields() {
        return String.join(
            new List<String>{
                'Id',
                'Name',
                'AccountNumber',
                'Type',
                'Industry',
                'AnnualRevenue',
                'NumberOfEmployees',
                'Phone',
                'Website',
                'OwnerId',
                'CreatedDate',
                'LastModifiedDate'
            },
            ', '
        );
    }

    /**
     * Returns fields needed for billing/territory operations
     * @return Comma-separated field list as a String
     */
    private static String getBillingFields() {
        return String.join(
            new List<String>{
                'Id',
                'Name',
                'BillingStreet',
                'BillingCity',
                'BillingState',
                'BillingPostalCode',
                'BillingCountry',
                'Territory__c'
            },
            ', '
        );
    }

    // ─── Query Methods ───────────────────────────────────────────────────

    /**
     * Selects Account records by their Ids
     * @param recordIds Set of Account Ids to query
     * @return List of Account records matching the provided Ids
     * @example
     * Set<Id> ids = new Set<Id>{ someAccountId };
     * List<Account> results = AccountSelector.selectByIds(ids);
     */
    public static List<Account> selectByIds(Set<Id> recordIds) {
        if (recordIds == null || recordIds.isEmpty()) {
            return new List<Account>();
        }

        return Database.query(
            'SELECT ' + getDefaultFields() +
            ' FROM Account' +
            ' WHERE Id IN :recordIds' +
            ' WITH USER_MODE'
        );
    }

    /**
     * Selects Account records as a Map keyed by Id
     * @param recordIds Set of Account Ids to query
     * @return Map of Id to Account
     */
    public static Map<Id, Account> selectMapByIds(Set<Id> recordIds) {
        return new Map<Id, Account>(selectByIds(recordIds));
    }

    /**
     * Selects Accounts with billing address fields for territory assignment
     * @param recordIds Set of Account Ids to query
     * @return List of Account records with billing address fields populated
     */
    public static List<Account> selectWithBillingAddress(Set<Id> recordIds) {
        if (recordIds == null || recordIds.isEmpty()) {
            return new List<Account>();
        }

        return Database.query(
            'SELECT ' + getBillingFields() +
            ' FROM Account' +
            ' WHERE Id IN :recordIds' +
            ' WITH USER_MODE'
        );
    }

    /**
     * Selects Accounts by Account Type
     * @param accountTypes Set of Account Type values to filter by
     * @return List of matching Account records
     * @example
     * List<Account> prospects = AccountSelector.selectByType(
     *     new Set<String>{ 'Prospect', 'Customer - Direct' }
     * );
     */
    public static List<Account> selectByType(Set<String> accountTypes) {
        if (accountTypes == null || accountTypes.isEmpty()) {
            return new List<Account>();
        }

        return Database.query(
            'SELECT ' + getDefaultFields() +
            ' FROM Account' +
            ' WHERE Type IN :accountTypes' +
            ' WITH USER_MODE' +
            ' ORDER BY Name ASC'
        );
    }

    /**
     * Selects Accounts by Industry with a minimum annual revenue
     * @param industries Set of Industry values to filter by
     * @param minRevenue Minimum AnnualRevenue threshold
     * @return List of matching Account records ordered by revenue descending
     * @example
     * List<Account> techAccounts = AccountSelector.selectByIndustryAndRevenue(
     *     new Set<String>{ 'Technology' },
     *     1000000
     * );
     */
    public static List<Account> selectByIndustryAndRevenue(Set<String> industries, Decimal minRevenue) {
        if (industries == null || industries.isEmpty()) {
            return new List<Account>();
        }

        Decimal revenueThreshold = minRevenue ?? 0;

        return Database.query(
            'SELECT ' + getDefaultFields() +
            ' FROM Account' +
            ' WHERE Industry IN :industries' +
            ' AND AnnualRevenue >= :revenueThreshold' +
            ' WITH USER_MODE' +
            ' ORDER BY AnnualRevenue DESC'
        );
    }

    /**
     * Selects Accounts with their related Contacts (subquery)
     * @param recordIds Set of Account Ids to query
     * @return List of Account records with nested Contacts
     */
    public static List<Account> selectWithContacts(Set<Id> recordIds) {
        if (recordIds == null || recordIds.isEmpty()) {
            return new List<Account>();
        }

        return [
            SELECT Id, Name, Type, Industry,
                   (SELECT Id, FirstName, LastName, Email, Title
                    FROM Contacts
                    ORDER BY LastName ASC)
            FROM Account
            WHERE Id IN :recordIds
            WITH USER_MODE
        ];
    }

    // ─── Aggregate Queries ───────────────────────────────────────────────

    /**
     * Returns a count of Accounts grouped by Industry
     * @return List of AggregateResult with Industry and record count
     * @example
     * List<AggregateResult> results = AccountSelector.countByIndustry();
     * for (AggregateResult ar : results) {
     *     System.debug(ar.get('Industry') + ': ' + ar.get('cnt'));
     * }
     */
    public static List<AggregateResult> countByIndustry() {
        return [
            SELECT Industry, COUNT(Id) cnt
            FROM Account
            WHERE Industry != NULL
            WITH USER_MODE
            GROUP BY Industry
            ORDER BY COUNT(Id) DESC
        ];
    }
}
