<?php
/**
 * Mail Server Client for WHP
 * Handles communication with mail server API for email account management
 * Based on the poste-dao-mail project structure
 */

class MailServerClient {
    private $base_url;
    private $username;
    private $password;
    private $timeout = 30;
    private $debug = false; // Add debug property
    
    public function __construct($base_url, $username, $password, $debug = false) {
        $this->base_url = rtrim($base_url, '/') . '/';
        $this->username = $username;
        $this->password = $password;
        $this->debug = $debug;
    }
    
    /**
     * Make HTTP request to mail server API
     */
    private function makeRequest($method, $endpoint, $data = null) {
        $url = $this->base_url . ltrim($endpoint, '/');
        $headers = [
            'Accept: application/json',
            'Content-Type: application/json'
        ];
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
        curl_setopt($ch, CURLOPT_USERPWD, $this->username . ":" . $this->password);
        
        switch ($method) {
            case 'GET':
                break;
            case 'POST':
                curl_setopt($ch, CURLOPT_POST, true);
                if ($data) {
                    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
                }
                break;
            case 'PUT':
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
                if ($data) {
                    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
                }
                break;
            case 'PATCH':
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
                if ($data) {
                    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
                }
                break;
            case 'DELETE':
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
                break;
        }
        
        // --- Begin debug logging ---
        if ($this->debug) {
            error_log("MailServerClient REQUEST: $method $url");
            error_log("Headers: " . json_encode($headers));
            if ($data) {
                error_log("Request body: " . json_encode($data));
            }
        }
        // --- End debug logging ---
        
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        // --- Begin debug logging ---
        if ($this->debug) {
            error_log("MailServerClient RESPONSE: HTTP $http_code");
            error_log("Response body: " . $response);
            if ($error) {
                error_log("cURL error: " . $error);
            }
        }
        // --- End debug logging ---
        
        if ($error) {
            throw new Exception("cURL Error: " . $error);
        }
        
        // Check if response is successful (2xx status codes)
        if (!preg_match('/^2/', $http_code)) {
            $error_message = "HTTP Error $http_code";
            if ($response) {
                $error_data = json_decode($response, true);
                if ($error_data && isset($error_data['message'])) {
                    $error_message .= ": " . $error_data['message'];
                } else {
                    $error_message .= ": " . $response;
                }
            }
            throw new Exception($error_message);
        }
        
        // Return null for 204 No Content, otherwise decode JSON
        return $http_code == 204 ? null : json_decode($response, true);
    }
    
    /**
     * Create a new email account
     */
    public function createEmailAccount($email, $password, $name, $quota_mb = 100) {
        $account_data = [
            'name' => $name,
            'email' => $email,
            'passwordPlaintext' => $password,
            'disabled' => false,
            'superAdmin' => false
        ];
        
        $response = $this->makeRequest('POST', 'boxes', $account_data);
        
        // Always set quota after account creation
        $quota_data = [
            'storageLimit' => $quota_mb
        ];
        $encoded_email = urlencode($email);
        $this->makeRequest('PATCH', "boxes/$encoded_email/quota", $quota_data);
        
        return $response;
    }
    
    /**
     * Create a new email forwarder (uses same endpoint as email accounts but with redirectTo)
     */
    public function createEmailForwarder($source_email, $destination_emails, $name = null) {
        // Ensure destination_emails is an array
        if (!is_array($destination_emails)) {
            $destination_emails = [$destination_emails];
        }
        
        $forwarder_data = [
            'name' => $name ?: explode('@', $source_email)[0],
            'email' => $source_email,
            'disabled' => false,
            'superAdmin' => false,
            'redirectTo' => $destination_emails
        ];
        
        return $this->makeRequest('POST', 'boxes', $forwarder_data);
    }

    /**
     * Update an email account (PUT method for full updates, PATCH for partial updates)
     */
    public function updateEmailAccount($email, $updates = [], $method = 'PUT') {
        $encoded_email = urlencode($email);
        return $this->makeRequest($method, "boxes/$encoded_email", $updates);
    }
    
    /**
     * Update email account settings (PATCH method for partial updates)
     */
    public function patchEmailAccount($email, $updates = []) {
        return $this->updateEmailAccount($email, $updates, 'PATCH');
    }
    
    /**
     * Get email account statistics
     */
    public function getEmailStats($email) {
        $encoded_email = urlencode($email);
        return $this->makeRequest('GET', "boxes/$encoded_email/stats");
    }
    
    /**
     * Delete an email account
     */
    public function deleteEmailAccount($email) {
        $encoded_email = urlencode($email);
        return $this->makeRequest('DELETE', "boxes/$encoded_email");
    }

    /**
     * Delete an email forwarder (uses same endpoint as email accounts)
     */
    public function deleteEmailForwarder($source_email) {
        $encoded_email = urlencode($source_email);
        return $this->makeRequest('DELETE', "boxes/$encoded_email");
    }
    
    /**
     * Get email account information
     */
    public function getEmailAccount($email) {
        $encoded_email = urlencode($email);
        return $this->makeRequest('GET', "boxes/$encoded_email");
    }
    
    /**
     * List all email accounts
     */
    public function listEmailAccounts() {
        return $this->makeRequest('GET', 'boxes');
    }
    
    /**
     * Create email alias
     */
    public function createEmailAlias($alias_email, $target_email) {
        $alias_data = [
            'address' => $alias_email,
            'forwardsTo' => [$target_email]
        ];
        
        return $this->makeRequest('POST', 'aliases', $alias_data);
    }
    
    /**
     * Delete email alias
     */
    public function deleteEmailAlias($alias_email) {
        $encoded_email = urlencode($alias_email);
        return $this->makeRequest('DELETE', "aliases/$encoded_email");
    }
    
    /**
     * List email aliases
     */
    public function listEmailAliases() {
        return $this->makeRequest('GET', 'aliases');
    }
    
    /**
     * Test connection to mail server
     */
    public function testConnection() {
        try {
            // Test connection using the boxes endpoint which should return 200
            $this->makeRequest('GET', 'boxes');
            return ['status' => 'success', 'message' => 'Connection successful - API accessible'];
        } catch (Exception $e) {
            $message = $e->getMessage();
            
            // Provide more helpful error messages
            if (strpos($message, '404') !== false) {
                $message = 'Mail server API endpoint not found. Please verify the API URL is correct and the mail server is running.';
            } elseif (strpos($message, '401') !== false || strpos($message, '403') !== false) {
                $message = 'Authentication failed. Please check your API username and password.';
            } elseif (strpos($message, 'Connection refused') !== false || strpos($message, 'Could not resolve') !== false) {
                $message = 'Cannot connect to mail server. Please check the API URL and ensure the mail server is accessible.';
            } elseif (strpos($message, 'timeout') !== false) {
                $message = 'Connection timeout. The mail server is not responding.';
            }
            
            return ['status' => 'error', 'message' => $message];
        }
    }
    
    /**
     * Get mail server statistics
     */
    public function getStatistics() {
        return $this->makeRequest('GET', 'stats');
    }
    
    /**
     * Create a new domain
     */
    public function createDomain($domain_name, $options = []) {
        $domain_data = [
            'name' => $domain_name,
            'disabled' => $options['disabled'] ?? false,
            'forward' => $options['forward'] ?? false,
            'forwardDomain' => $options['forward_domain'] ?? null,
            'domainBin' => $options['domain_bin'] ?? false,
            'domainBinAddress' => $options['domain_bin_address'] ?? null,
            'forceRoute' => $options['force_route'] ?? false,
            'forceRouteHost' => $options['force_route_host'] ?? null,
            'customOutbound' => $options['custom_outbound'] ?? false,
            'outboundIP' => $options['outbound_ip'] ?? null,
            'outboundEhlo' => $options['outbound_ehlo'] ?? null,
            'referenceId' => $options['reference_id'] ?? null
        ];
        
        // Remove null values
        $domain_data = array_filter($domain_data, function($value) {
            return $value !== null;
        });
        
        return $this->makeRequest('POST', 'domains', $domain_data);
    }
    
    /**
     * Get domain information
     */
    public function getDomain($domain_name) {
        return $this->makeRequest('GET', "domains/$domain_name");
    }
    
    /**
     * List all domains
     */
    public function listDomains() {
        return $this->makeRequest('GET', 'domains');
    }
    
    /**
     * Delete a domain and all its email addresses
     */
    public function deleteDomain($domain_name) {
        return $this->makeRequest('DELETE', "domains/$domain_name");
    }
    
    /**
     * Update domain settings
     */
    public function updateDomain($domain_name, $updates = []) {
        // Map WHP field names to API field names
        $api_updates = [];
        
        if (isset($updates['forward'])) {
            $api_updates['forward'] = $updates['forward'];
        }
        if (isset($updates['forward_domain'])) {
            $api_updates['forwardDomain'] = $updates['forward_domain'];
        }
        if (isset($updates['domain_bin'])) {
            $api_updates['domainBin'] = $updates['domain_bin'];
        }
        if (isset($updates['domain_bin_address'])) {
            $api_updates['domainBinAddress'] = $updates['domain_bin_address'];
        }
        if (isset($updates['force_route'])) {
            $api_updates['forceRoute'] = $updates['force_route'];
        }
        if (isset($updates['force_route_host'])) {
            $api_updates['forceRouteHost'] = $updates['force_route_host'];
        }
        if (isset($updates['custom_outbound'])) {
            $api_updates['customOutbound'] = $updates['custom_outbound'];
        }
        if (isset($updates['outbound_ip'])) {
            $api_updates['outboundIP'] = $updates['outbound_ip'];
        }
        if (isset($updates['outbound_ehlo'])) {
            $api_updates['outboundEhlo'] = $updates['outbound_ehlo'];
        }
        if (isset($updates['reference_id'])) {
            $api_updates['referenceId'] = $updates['reference_id'];
        }
        if (isset($updates['disabled'])) {
            $api_updates['disabled'] = $updates['disabled'];
        }
        if (isset($updates['name'])) {
            $api_updates['name'] = $updates['name'];
        }
        
        return $this->makeRequest('PATCH', "domains/$domain_name", $api_updates);
    }
    
    /**
     * Create DKIM records for a domain
     */
    public function createDkimRecords($domain_name) {
        return $this->makeRequest('PUT', "domains/$domain_name/dkim");
    }
    
    /**
     * Get DKIM records for a domain
     */
    public function getDkimRecords($domain_name) {
        return $this->makeRequest('GET', "domains/$domain_name/dkim");
    }
    
    /**
     * Delete DKIM records for a domain
     */
    public function deleteDkimRecords($domain_name) {
        return $this->makeRequest('DELETE', "domains/$domain_name/dkim");
    }
    
    /**
     * Update email account quota
     */
    public function updateEmailQuota($email, $storage_limit_mb) {
        $quota_data = [
            'storageLimit' => $storage_limit_mb
        ];
        
        $encoded_email = urlencode($email);
        return $this->makeRequest('PATCH', "boxes/$encoded_email/quota", $quota_data);
    }
    
    /**
     * Get email accounts from mail server with optional domain filter
     * @param string $domain Domain to filter by (optional)
     * @param int $page Page number (default 1)
     * @param int $paging Number of results per page (default 500)
     * @return array Response from mail server API
     */
    public function getEmailAccounts($domain = null, $page = 1, $paging = 500) {
        $params = [
            'page' => $page,
            'paging' => $paging
        ];
        
        if ($domain) {
            $params['query'] = $domain;
        }
        
        $query = http_build_query($params);
        return $this->makeRequest('GET', "boxes?$query");
    }

    
    /**
     * Validate email address format
     */
    public static function validateEmail($email) {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return false;
        }
        
        // Check for prohibited usernames
        $prohibited_usernames = [
            'abuse', 'spam', 'phish', 'scam', 'hack', 'admin', 'root', 'system', 
            'postmaster', 'webmaster', 'hostmaster', 'support', 'info', 'sales', 
            'contact', 'security', 'billing', 'help', 'noreply', 'mail', 'smtp', 
            'pop', 'imap', 'test', 'test-user'
        ];
        
        $username = strtolower(explode('@', $email)[0]);
        foreach ($prohibited_usernames as $prohibited) {
            if ($username === $prohibited) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * Validate username format
     */
    public static function validateUsername($username) {
        // Username must be 3-32 characters
        if (strlen($username) < 3 || strlen($username) > 32) {
            return false;
        }
        
        // Username must contain only letters, numbers, dots, underscores, or hyphens
        if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9]$/', $username)) {
            return false;
        }
        
        // Check for prohibited usernames
        $prohibited_usernames = [
            'abuse', 'spam', 'phish', 'scam', 'hack', 'gay', 'fag', 'homo', 'sex', 
            'porn', 'xxx', 'fuck', 'shit', 'dick', 'penis', 'vagina', 'ass', 'bitch', 
            'cunt', 'rape', 'nazi', 'kill', 'murder', 'terrorist', 'jihad', 'slave', 
            'nigger', 'nigga', 'whore', 'slut', 'bastard', 'retard', 'faggot', 'pedo', 
            'pederast', 'cock', 'piss', 'tits', 'boob', 'cum', 'wank', 'jerk', 'anal', 
            'anus', 'racist', 'puta', 'puto', 'mierda', 'verga', 'pinga', 'coño', 
            'joto', 'maricon', 'perra', 'zorra', 'paki', 'chink', 'gook', 'kike', 
            'spic', 'dyke', 'lesbo', 'tranny', 'allah', 'jihadi', 'isis', 'satan', 
            'devil', 'god', 'jesus', 'admin', 'root', 'system', 'postmaster', 
            'webmaster', 'hostmaster', 'support', 'info', 'sales', 'contact', 
            'abuse', 'security', 'billing', 'help', 'noreply', 'mail', 'smtp', 
            'pop', 'imap', 'test', 'test-user'
        ];
        
        $username_lower = strtolower($username);
        foreach ($prohibited_usernames as $prohibited) {
            if (strpos($username_lower, $prohibited) !== false) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * Get mail server configuration from settings
     */
    public static function getMailServerConfig() {
        $config_file = '/docker/whp/settings.json';
        if (!file_exists($config_file)) {
            throw new Exception('Mail server configuration not found. Please configure mail server settings in the Server Settings page.');
        }
        
        $config = json_decode(file_get_contents($config_file), true);
        if (!$config) {
            throw new Exception('Invalid mail server configuration');
        }
        
        $required_fields = ['mail_api_url', 'mail_api_username', 'mail_api_password'];
        foreach ($required_fields as $field) {
            if (empty($config[$field])) {
                throw new Exception("Missing required field: $field. Please configure mail server settings in the Server Settings page.");
            }
        }
        
        // Check for placeholder values
        $placeholder_values = [
            'mail_api_url' => 'https://your-mail-server.com/admin/api/v1/',
            'mail_api_username' => 'your-api-username',
            'mail_api_password' => 'your-api-password'
        ];
        
        foreach ($placeholder_values as $field => $placeholder) {
            if ($config[$field] === $placeholder) {
                throw new Exception("Mail server configuration not configured. Please update the $field field in the Server Settings page with your actual mail server API details.");
            }
        }
        
        // Add debug flag (default to false if not set)
        $config['mailserver_debug_log'] = !empty($config['mailserver_debug_log']);
        
        return $config;
    }
    
    /**
     * Create mail server client instance from configuration
     */
    public static function createFromConfig() {
        $config = self::getMailServerConfig();
        return new self(
            $config['mail_api_url'],
            $config['mail_api_username'],
            $config['mail_api_password'],
            $config['mailserver_debug_log'] ?? false
        );
    }
}
?> 