<?php
/**
 * Currencies REST API Controller.
 *
 * Endpoints:
 *   GET    /titancart/v1/currencies           List all currencies
 *   POST   /titancart/v1/currencies           Create a currency
 *   GET    /titancart/v1/currencies/{id}      Get single currency
 *   PUT    /titancart/v1/currencies/{id}      Update a currency
 *   DELETE /titancart/v1/currencies/{id}      Delete a currency
 *
 * @package TitanCart\REST\Settings
 */

namespace TitanCart\REST\Settings;

use TitanCart\DB\Database;
use TitanCart\Core\LogService;
use TitanCart\Services\CurrencyService;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

defined( 'ABSPATH' ) || exit;

class CurrenciesController {

    private string $namespace = 'titancart/v1';
    private Database $db;

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

    public function register_routes(): void {

        register_rest_route( $this->namespace, '/currencies', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_currencies' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'create_currency' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

        register_rest_route( $this->namespace, '/currencies/(?P<id>\d+)', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_currency' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
            [
                'methods'             => WP_REST_Server::EDITABLE,
                'callback'            => [ $this, 'update_currency' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
            [
                'methods'             => WP_REST_Server::DELETABLE,
                'callback'            => [ $this, 'delete_currency' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );
    }

    // ══════════════════════════════════════════════════════════════════════════
    // HANDLERS
    // ══════════════════════════════════════════════════════════════════════════

    /** GET /currencies */
    public function get_currencies( WP_REST_Request $request ): WP_REST_Response {
        $rows = $this->db->getArray(
            "SELECT * FROM {$this->db->table('currencies')} ORDER BY position ASC, id ASC"
        );
        return new WP_REST_Response( $rows );
    }

    /** GET /currencies/{id} */
    public function get_currency( WP_REST_Request $request ): WP_REST_Response|WP_Error {
        $id  = (int) $request->get_param( 'id' );
        $row = $this->db->getRow(
            "SELECT * FROM {$this->db->table('currencies')} WHERE id = ?i LIMIT 1",
            $id
        );
        if ( ! $row ) {
            return new WP_Error( 'tc_not_found', __( 'Currency not found.', 'titancart-lite' ), [ 'status' => 404 ] );
        }
        return new WP_REST_Response( $row );
    }

    /** POST /currencies */
    public function create_currency( WP_REST_Request $request ): WP_REST_Response|WP_Error {
        $body = $request->get_json_params() ?: [];

        $code = strtoupper( sanitize_text_field( $body['code'] ?? '' ) );
        $name = sanitize_text_field( $body['name'] ?? '' );

        if ( ! $code || strlen( $code ) !== 3 ) {
            return new WP_Error( 'tc_invalid', __( 'A valid 3-letter currency code is required.', 'titancart-lite' ), [ 'status' => 422 ] );
        }
        if ( ! $name ) {
            return new WP_Error( 'tc_invalid', __( 'Currency name is required.', 'titancart-lite' ), [ 'status' => 422 ] );
        }

        // Check for duplicate code.
        $existing = $this->db->getField(
            "SELECT id FROM {$this->db->table('currencies')} WHERE code = ?s LIMIT 1",
            $code
        );
        if ( $existing ) {
            return new WP_Error( 'tc_duplicate', __( 'A currency with this code already exists.', 'titancart-lite' ), [ 'status' => 422 ] );
        }

        $is_primary = ! empty( $body['is_primary'] ) ? 1 : 0;

        // If this is set as primary, unset any other primary.
        if ( $is_primary ) {
            $this->db->query( "UPDATE {$this->db->table('currencies')} SET is_primary = 0" );
        }

        $data = [
            'code'          => $code,
            'name'          => $name,
            'symbol'        => sanitize_text_field( $body['symbol'] ?? '' ),
            'symbol_after'  => ! empty( $body['symbol_after'] ) ? 1 : 0,
            'decimals'      => isset( $body['decimals'] ) ? (int) $body['decimals'] : 2,
            'thousands_sep' => $body['thousands_sep'] ?? ',',
            'decimal_sep'   => $body['decimal_sep'] ?? '.',
            'exchange_rate' => isset( $body['exchange_rate'] ) ? (float) $body['exchange_rate'] : 1.0,
            'is_primary'    => $is_primary,
            'position'      => isset( $body['position'] ) ? (int) $body['position'] : 0,
            'status'        => ( $body['status'] ?? 'active' ) === 'disabled' ? 'disabled' : 'active',
        ];

        $this->db->insert( 'currencies', $data );
        $id = $this->db->lastInsertId();

        if ( ! $id ) {
            return new WP_Error( 'tc_create_failed', __( 'Failed to create currency.', 'titancart-lite' ), [ 'status' => 500 ] );
        }

        LogService::info( 'general', 'create', 'Currency created: ' . $code . ' — ' . $name . ' (#' . $id . ')', [
            'object_type' => 'currency',
            'object_id'   => $id,
            'code'        => $code,
        ] );

        // S120: Flush CurrencyService cache so the next request reads the new state.
        CurrencyService::flush();

        return new WP_REST_Response( $this->db->getRow(
            "SELECT * FROM {$this->db->table('currencies')} WHERE id = ?i LIMIT 1", $id
        ), 201 );
    }

    /** PUT /currencies/{id} */
    public function update_currency( WP_REST_Request $request ): WP_REST_Response|WP_Error {
        $id   = (int) $request->get_param( 'id' );
        $body = $request->get_json_params() ?: [];

        $row = $this->db->getRow(
            "SELECT * FROM {$this->db->table('currencies')} WHERE id = ?i LIMIT 1", $id
        );
        if ( ! $row ) {
            return new WP_Error( 'tc_not_found', __( 'Currency not found.', 'titancart-lite' ), [ 'status' => 404 ] );
        }

        // Cannot disable the primary currency.
        if ( (int) $row['is_primary'] === 1 && ( $body['status'] ?? '' ) === 'disabled' ) {
            return new WP_Error( 'tc_forbidden', __( 'Cannot disable the primary currency. Set another currency as primary first.', 'titancart-lite' ), [ 'status' => 422 ] );
        }

        $set = [];
        if ( isset( $body['name'] ) )          $set['name']          = sanitize_text_field( $body['name'] );
        if ( isset( $body['symbol'] ) )        $set['symbol']        = sanitize_text_field( $body['symbol'] );
        if ( isset( $body['symbol_after'] ) )  $set['symbol_after']  = ! empty( $body['symbol_after'] ) ? 1 : 0;
        if ( isset( $body['decimals'] ) )      $set['decimals']      = (int) $body['decimals'];
        if ( isset( $body['thousands_sep'] ) ) $set['thousands_sep'] = $body['thousands_sep'];
        if ( isset( $body['decimal_sep'] ) )   $set['decimal_sep']   = $body['decimal_sep'];
        if ( isset( $body['exchange_rate'] ) ) $set['exchange_rate'] = (float) $body['exchange_rate'];
        if ( isset( $body['position'] ) )      $set['position']      = (int) $body['position'];
        if ( isset( $body['status'] ) )        $set['status']        = $body['status'] === 'disabled' ? 'disabled' : 'active';

        // Handle primary change.
        if ( isset( $body['is_primary'] ) ) {
            $new_primary = ! empty( $body['is_primary'] ) ? 1 : 0;
            if ( $new_primary && ! (int) $row['is_primary'] ) {
                // Unset all others.
                $this->db->query( "UPDATE {$this->db->table('currencies')} SET is_primary = 0" );
                $set['is_primary'] = 1;
                $set['exchange_rate'] = 1.0; // Primary is always 1.0.
            } elseif ( ! $new_primary && (int) $row['is_primary'] ) {
                // Can't remove primary without setting another.
                return new WP_Error( 'tc_forbidden', __( 'Cannot remove primary status. Set another currency as primary instead.', 'titancart-lite' ), [ 'status' => 422 ] );
            }
        }

        if ( ! empty( $set ) ) {
            $this->db->update( 'currencies', $set, [ 'id' => $id ] );
        }

        LogService::info( 'general', 'update', 'Currency updated: ' . $row['code'] . ' (#' . $id . ')', [
            'object_type' => 'currency',
            'object_id'   => $id,
            'code'        => $row['code'],
        ] );

        // S120: Flush CurrencyService cache — primary symbol/decimals/etc. may have changed.
        CurrencyService::flush();

        return new WP_REST_Response( $this->db->getRow(
            "SELECT * FROM {$this->db->table('currencies')} WHERE id = ?i LIMIT 1", $id
        ) );
    }

    /** DELETE /currencies/{id} */
    public function delete_currency( WP_REST_Request $request ): WP_REST_Response|WP_Error {
        $id  = (int) $request->get_param( 'id' );
        $row = $this->db->getRow(
            "SELECT * FROM {$this->db->table('currencies')} WHERE id = ?i LIMIT 1", $id
        );
        if ( ! $row ) {
            return new WP_Error( 'tc_not_found', __( 'Currency not found.', 'titancart-lite' ), [ 'status' => 404 ] );
        }
        if ( (int) $row['is_primary'] === 1 ) {
            return new WP_Error( 'tc_forbidden', __( 'Cannot delete the primary currency. Set another currency as primary first.', 'titancart-lite' ), [ 'status' => 422 ] );
        }

        $this->db->query(
            "DELETE FROM {$this->db->table('currencies')} WHERE id = ?i LIMIT 1", $id
        );

        LogService::info( 'general', 'delete', 'Currency deleted: ' . $row['code'] . ' (#' . $id . ')', [
            'object_type' => 'currency',
            'object_id'   => $id,
            'code'        => $row['code'],
        ] );

        // S120: Flush CurrencyService cache — although delete() blocks deleting the primary,
        // the active set has changed and the secondary fallback path may now resolve differently.
        CurrencyService::flush();

        return new WP_REST_Response( [ 'deleted' => true, 'id' => $id ] );
    }

    // ══════════════════════════════════════════════════════════════════════════
    // PERMISSIONS
    // ══════════════════════════════════════════════════════════════════════════

    public function admin_permission(): bool {
        return current_user_can( 'manage_options' );
    }
}
