<?php
defined('ABSPATH') or die('Direct access not allowed');

/**
 * VollstartRD_Customers — Customer CRUD.
 *
 * SRP: Creates, reads, updates, deletes customers.
 * Generates customer numbers with configurable prefix.
 */
class VollstartRD_Customers {

    private $MAIN;

    public function __construct($MAIN) {
        $this->MAIN = $MAIN;
    }

    /**
     * Create a new customer.
     * @return int Customer ID
     */
    public function create(array $data): int {
        $fields = [
            'name'    => sanitize_text_field($data['name'] ?? ''),
            'email'   => sanitize_email($data['email'] ?? ''),
            'phone'   => sanitize_text_field($data['phone'] ?? ''),
            'address'    => sanitize_textarea_field($data['address'] ?? ''),
            'vat_number' => sanitize_text_field($data['vat_number'] ?? ''),
            'notes'      => sanitize_textarea_field($data['notes'] ?? ''),
            'created_at' => current_time('mysql'),
        ];

        $id = $this->MAIN->getDB()->insert('customers', $fields);

        // Generate customer number
        $prefix = $this->MAIN->getOptions()->getOptionValue('customerNumberPrefix') ?: 'KD-';
        $number = $prefix . str_pad($id, 4, '0', STR_PAD_LEFT);
        $this->MAIN->getDB()->update('customers', ['customer_number' => $number], ['id' => $id]);

        $this->logChange($id, '_created', '', $fields['name']);

        return $id;
    }

    /**
     * Update an existing customer.
     */
    public function update(int $id, array $data): bool {
        $old = $this->getById($id);

        $fields = [];
        if (isset($data['name'])) $fields['name'] = sanitize_text_field($data['name']);
        if (isset($data['email'])) $fields['email'] = sanitize_email($data['email']);
        if (isset($data['phone'])) $fields['phone'] = sanitize_text_field($data['phone']);
        if (isset($data['address'])) $fields['address'] = sanitize_textarea_field($data['address']);
        if (isset($data['vat_number'])) $fields['vat_number'] = sanitize_text_field($data['vat_number']);
        if (isset($data['notes'])) $fields['notes'] = sanitize_textarea_field($data['notes']);

        if (empty($fields)) {
            return false;
        }

        $result = $this->MAIN->getDB()->update('customers', $fields, ['id' => $id]) !== false;

        // Log changes
        if ($result && $old) {
            foreach ($fields as $key => $newVal) {
                $oldVal = $old[$key] ?? '';
                if ((string) $oldVal !== (string) $newVal) {
                    $this->logChange($id, $key, $oldVal, $newVal);
                }
            }
        }

        return $result;
    }

    /**
     * Log a field change to customer_history.
     */
    private function logChange(int $customerId, string $field, string $oldValue, string $newValue): void {
        try {
            $this->MAIN->getDB()->insert('customer_history', [
                'customer_id' => $customerId,
                'field_name'  => $field,
                'old_value'   => $oldValue,
                'new_value'   => $newValue,
                'changed_by'  => get_current_user_id(),
                'changed_at'  => wp_date('Y-m-d H:i:s'),
            ]);
        } catch (\Exception $e) {
            // silently ignore
        }
    }

    /**
     * Get change history for a customer.
     */
    public function getHistory(int $customerId): array {
        $db = $this->MAIN->getDB();
        global $wpdb;
        $tbl = $db->getTabelle('customer_history');
        return $db->getResults(
            "SELECT h.*, u.display_name AS changed_by_name FROM %i h LEFT JOIN {$wpdb->users} u ON h.changed_by = u.ID WHERE h.customer_id = %d ORDER BY h.changed_at DESC",
            $tbl, $customerId
        );
    }

    /**
     * Get a single customer by ID.
     */
    public function getById(int $id): ?array {
        $db = $this->MAIN->getDB();
        $tbl = $db->getTabelle('customers');
        return $db->getRow("SELECT * FROM %i WHERE id = %d", $tbl, $id);
    }

    /**
     * Get all customers.
     */
    public function getAll(): array {
        $db = $this->MAIN->getDB();
        $tbl = $db->getTabelle('customers');
        return $db->getResults("SELECT * FROM %i ORDER BY name ASC", $tbl);
    }

    /**
     * Search customers by name, email, phone, or customer number.
     */
    public function search(string $query): array {
        $db = $this->MAIN->getDB();
        $tbl = $db->getTabelle('customers');
        $like = '%' . $db->escLike($query) . '%';
        return $db->getResults(
            "SELECT * FROM %i WHERE name LIKE %s OR email LIKE %s OR phone LIKE %s OR customer_number LIKE %s ORDER BY name ASC",
            $tbl, $like, $like, $like, $like
        );
    }

    /**
     * Delete a customer.
     */
    public function delete(int $id): bool {
        return $this->MAIN->getDB()->delete('customers', ['id' => $id]) !== false;
    }

    /**
     * GDPR: Anonymize customer — wipe personal data but keep repairs intact.
     * Repairs stay for business records, but customer details are removed.
     */
    public function anonymize(int $id): bool {
        $db = $this->MAIN->getDB();
        $customer = $this->getById($id);
        if (!$customer) return false;

        // Anonymize customer record
        $db->update('customers', [
            'name'         => __('Deleted Customer', 'vollstart-repair-desk'),
            'email'        => '',
            'phone'        => '',
            'address'      => '',
            'notes'        => '',
        ], ['id' => $id]);

        // Clear customer history
        $db->delete('customer_history', ['customer_id' => $id]);

        // Anonymize messages from this customer
        $repairs = $db->getResults("SELECT id FROM %i WHERE customer_id = %d", $db->getTabelle('repairs'), $id);
        $msgTbl = $db->getTabelle('messages');
        foreach ($repairs as $r) {
            $db->rawQuery(
                "UPDATE %i SET sender_name = %s WHERE repair_id = %d AND sender_type = 'customer'",
                $msgTbl, __('Deleted Customer', 'vollstart-repair-desk'), (int) $r['id']
            );
        }

        // Anonymize devices: wipe details + delete photos
        $products = $db->getResults("SELECT id FROM %i WHERE customer_id = %d", $db->getTabelle('products'), $id);
        foreach ($products as $p) {
            $this->MAIN->getFileUpload()->deleteByEntity('product', (int) $p['id']);
            $db->update('products', [
                'name'          => '',
                'brand'         => '',
                'model'         => '',
                'serial_number' => '',
                'notes'         => '',
            ], ['id' => (int) $p['id']]);
        }
        $db->delete('product_history', ['customer_id' => $id]);

        // Log GDPR note on each repair
        foreach ($repairs as $r) {
            $this->MAIN->getRepairs()->logEvent(
                (int) $r['id'], 'gdpr_anonymized', '',
                __('Customer data erased (GDPR deletion request)', 'vollstart-repair-desk'),
                $customer['name'], __('Deleted Customer', 'vollstart-repair-desk')
            );
        }

        return true;
    }

    /**
     * Export all customer data as array (GDPR data export).
     */
    public function exportCustomerData(int $id): ?array {
        $customer = $this->getById($id);
        if (!$customer) return null;

        $db = $this->MAIN->getDB();

        // Repairs
        $repairs = $db->getResults("SELECT * FROM %i WHERE customer_id = %d ORDER BY created_at DESC", $db->getTabelle('repairs'), $id);
        foreach ($repairs as &$r) {
            unset($r['access_code']); // Don't export security code
            $r['status_log'] = $db->getResults("SELECT event_type, old_status, new_status, note, created_at FROM %i WHERE repair_id = %d ORDER BY created_at ASC", $db->getTabelle('status_log'), (int) $r['id']);
            $r['messages'] = $db->getResults("SELECT sender_type, sender_name, message, created_at FROM %i WHERE repair_id = %d ORDER BY created_at ASC", $db->getTabelle('messages'), (int) $r['id']);
        }

        // Products/Devices
        $products = $db->getResults("SELECT * FROM %i WHERE customer_id = %d ORDER BY created_at DESC", $db->getTabelle('products'), $id);

        return [
            'export_date' => current_time('mysql'),
            'plugin'      => 'Vollstart Repair Desk',
            'customer'    => $customer,
            'repairs'     => $repairs,
            'devices'     => $products,
        ];
    }

    /**
     * Count all customers.
     */
    public function count(): int {
        return $this->MAIN->getDB()->count('customers');
    }

    /**
     * Server-side paginated list for DataTables.
     */
    public function getPaginated(array $params): array {
        $db = $this->MAIN->getDB();
        $tbl = $db->getTabelle('customers');
        $rtbl = $db->getTabelle('repairs');
        $ptbl = $db->getTabelle('products');

        $page = max(1, (int) ($params['page'] ?? 1));
        $perPage = max(1, min(100, (int) ($params['per_page'] ?? 20)));
        $offset = ($page - 1) * $perPage;
        $search = $params['search'] ?? '';
        $orderBy = $params['orderby'] ?? 'name';
        $order = strtoupper($params['order'] ?? 'ASC') === 'DESC' ? 'DESC' : 'ASC';

        // Whitelist sortable columns
        $sortable = ['customer_number', 'name', 'email', 'phone', 'created_at', 'repair_count', 'product_count'];
        if (!in_array($orderBy, $sortable)) {
            $orderBy = 'name';
        }

        global $wpdb;

        $where = '';
        $whereValues = [];
        if (!empty($search)) {
            $like = '%' . $db->escLike($search) . '%';
            $where = "WHERE (c.name LIKE %s OR c.email LIKE %s OR c.phone LIKE %s OR c.customer_number LIKE %s)";
            $whereValues = [$like, $like, $like, $like];
        }

        // Count total
        $total = (int) $db->getVar("SELECT COUNT(*) FROM %i", $tbl);

        // Count filtered
        if (!empty($where)) {
            $filteredSql = "SELECT COUNT(*) FROM %i c {$where}";
            $filtered = (int) $db->getVar($filteredSql, ...array_merge([$tbl], $whereValues));
        } else {
            $filtered = $total;
        }

        // Subquery counts (no JOINs, faster)
        $orderClause = in_array($orderBy, ['repair_count', 'product_count'])
            ? "{$orderBy} {$order}"
            : "c.{$orderBy} {$order}";

        $sql = "SELECT c.*,
                    (SELECT COUNT(*) FROM {$rtbl} WHERE customer_id = c.id) AS repair_count,
                    (SELECT COUNT(*) FROM {$ptbl} WHERE customer_id = c.id) AS product_count
                FROM %i c
                {$where}
                ORDER BY {$orderClause}
                LIMIT %d, %d";

        $values = array_merge([$tbl], $whereValues, [$offset, $perPage]);
        $rows = $db->getResults($sql, ...$values);

        return [
            'customers' => $rows,
            'total'     => $total,
            'filtered'  => $filtered,
        ];
    }

    /**
     * Get customers for dropdown (id + name + customer_number).
     */
    public function getForDropdown(): array {
        $db = $this->MAIN->getDB();
        $tbl = $db->getTabelle('customers');
        return $db->getResults("SELECT id, customer_number, name, email, phone FROM %i ORDER BY name ASC", $tbl);
    }

}
