<?php

namespace App\Services\Character;

use App\Services\Api\API;

class CharacterActionService
{
    protected API $api;

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

    /**
     * Ban or mute a character
     */
    public function punishCharacter(int $roleId, array $data): array
    {
        $banType = $data['type'] ?? 'ban';
        $reason = $data['reason'] ?? ($banType === 'mute' ? 'Muted by admin' : 'Banned by admin');
        $duration = $data['duration'] ?? 0;

        if ($banType === 'mute') {
            $this->api->muteRole($roleId, $duration, $reason);
        } else {
            $this->api->forbidRole($roleId, $duration, $reason);
        }

        return [
            'success' => true,
            'message' => $this->formatPunishmentMessage($banType, $duration),
        ];
    }

    /**
     * Send mail to character
     */
    public function sendMail(int $roleId, array $data): array
    {
        $item = [];
        if (($data['item_id'] ?? 0) > 0) {
            $item = [
                'id' => $data['item_id'],
                'pos' => 0,
                'count' => $data['item_count'] ?? 1,
                'max_count' => $data['max_count'] ?? 50000,
                'data' => $data['item_data'] ?? '',
                'proctype' => 0,
                'expire_date' => 0,
                'guid1' => 0,
                'guid2' => 0,
                'mask' => 0,
            ];
        }

        $result = $this->api->sendMail(
            $roleId,
            $data['title'],
            $data['message'],
            $data['gold'] ?? 0,
            $item
        );

        return [
            'success' => $result !== false,
            'message' => $result !== false ? 'Mail sent successfully' : 'Failed to send mail',
        ];
    }

    /**
     * Teleport character to position
     */
    public function teleportCharacter(int $roleId, array $position): array
    {
        $result = $this->api->teleportRole(
            $roleId,
            (float) $position['posx'],
            (float) $position['posy'],
            (float) $position['posz'],
            (int) $position['worldtag']
        );

        return [
            'success' => $result['success'],
            'message' => $result['message'] ?? 'Teleport completed',
        ];
    }

    /**
     * Clone character data
     */
    public function cloneCharacter(int $sourceRoleId, int $targetRoleId, array $sections): array
    {
        // Check if roles are online
        $onlineCheck = $this->checkCharactersOnline($sourceRoleId, $targetRoleId);
        if (! $onlineCheck['success']) {
            return $onlineCheck;
        }

        // Verify both roles exist
        $roleCheck = $this->validateRoles($sourceRoleId, $targetRoleId);
        if (! $roleCheck['success']) {
            return $roleCheck;
        }

        // The admin UI exposes explicit section checkboxes, so the clone operation
        // should always follow that exact section list instead of silently cloning
        // extra role data when all boxes happen to be selected.
        $results = $this->processPartialClone($sourceRoleId, $targetRoleId, $sections);

        return $this->formatCloneResult($sourceRoleId, $targetRoleId, $results);
    }

    /**
     * Get online characters
     */
    public function getOnlineCharacters(): array
    {
        $onlineList = $this->api->getOnlineList();

        $characters = [];
        foreach ($onlineList as $online) {
            $roleId = $online['roleid'] ?? 0;
            if ($roleId > 0) {
                $characters[] = [
                    'id' => $roleId,
                    'name' => $online['name'] ?? '',
                    'user_id' => $online['userid'] ?? 0,
                ];
            }
        }

        return [
            'characters' => $characters,
            'count' => count($characters),
        ];
    }

    /**
     * Format punishment message
     */
    private function formatPunishmentMessage(string $banType, int $duration): string
    {
        $durationText = match (true) {
            $duration === 0 => 'permanently',
            $duration < 60 => $duration.' seconds',
            $duration < 3600 => floor($duration / 60).' minutes',
            $duration < 86400 => floor($duration / 3600).' hours',
            default => floor($duration / 86400).' days',
        };

        $actionText = $banType === 'mute' ? 'muted' : 'banned';

        return "Character {$actionText} {$durationText} successfully";
    }

    /**
     * Check if characters are online
     */
    private function checkCharactersOnline(int $sourceRoleId, int $targetRoleId): array
    {
        $onlineList = $this->api->getOnlineList() ?? [];

        foreach ($onlineList as $player) {
            $roleid = $player['roleid'] ?? 0;
            if ($roleid == $sourceRoleId) {
                return ['success' => false, 'error' => 'Source character is online. Please wait until they logout.'];
            }
            if ($roleid == $targetRoleId) {
                return ['success' => false, 'error' => 'Target character is online. Please wait until they logout.'];
            }
        }

        return ['success' => true];
    }

    /**
     * Validate that both roles exist
     */
    private function validateRoles(int $sourceRoleId, int $targetRoleId): array
    {
        $sourceBase = $this->api->getRoleBase($sourceRoleId);
        $targetBase = $this->api->getRoleBase($targetRoleId);

        if (! $sourceBase || ! isset($sourceBase['id'])) {
            return ['success' => false, 'error' => 'Source role not found'];
        }
        if (! $targetBase || ! isset($targetBase['id'])) {
            return ['success' => false, 'error' => 'Target role not found'];
        }

        return ['success' => true];
    }

    /**
     * Process partial clone sections
     */
    private function processPartialClone(int $sourceRoleId, int $targetRoleId, array $sections): array
    {
        $results = [];

        // Clone base (status fields like level, exp, sp, etc.)
        if (in_array('base', $sections)) {
            $results['base'] = $this->cloneBaseFields($sourceRoleId, $targetRoleId);
        }

        // Clone other sections
        $sectionMethods = [
            'pocket' => 'cloneSection',
            'equipment' => 'cloneSection',
            'storehouse' => 'cloneSection',
        ];

        foreach ($sectionMethods as $section => $method) {
            if (in_array($section, $sections)) {
                $result = $this->api->{$method}($sourceRoleId, $targetRoleId, $section);
                $results[$section] = $result['success'] ? 'success' : ($result['message'] ?? 'failed');
            }
        }

        return $results;
    }

    /**
     * Clone base status fields
     */
    private function cloneBaseFields(int $sourceRoleId, int $targetRoleId): string
    {
        $baseResult = $this->api->cloneRoleBaseProtocol($sourceRoleId, $targetRoleId);

        if ($baseResult['success']) {
            return 'success';
        }

        return 'failed - '.($baseResult['message'] ?? 'base clone failed');
    }

    /**
     * Format clone result
     */
    private function formatCloneResult(int $sourceRoleId, int $targetRoleId, array $results): array
    {
        $sourceBase = $this->api->getRoleBase($sourceRoleId);
        $targetBase = $this->api->getRoleBase($targetRoleId);

        $allSuccess = ! in_array('failed', array_map(fn ($v) => str_contains($v, 'failed') ? 'failed' : 'ok', $results));

        return [
            'success' => $allSuccess,
            'message' => $allSuccess ? 'Clone completed successfully' : 'Clone completed with some errors',
            'results' => $results,
            'source' => $sourceBase['name'] ?? $sourceRoleId,
            'target' => $targetBase['name'] ?? $targetRoleId,
        ];
    }
}
