Implement KingdomController and PurchaseController - Core API Layer

Major API controllers completed:
 KingdomController - Democratic leadership, KvK events, population management, kingdom mergers
 PurchaseController - Ethical monetization, anti-pay-to-win monitoring, VIP systems, player protection

Key features implemented:
- Democratic KvK host selection and event coordination
- Anti-pay-to-win balance validation (<30% spending influence)
- Skill-based alternatives ensuring 70% F2P competitive effectiveness
- Ethical monetization with player welfare protection systems
- VIP secret tier handling with chargeback protection
- Revenue analytics balancing business goals with player satisfaction

Technical implementation:
- RESTful API design with proper HTTP status codes
- JWT authentication with kingdom-scoped security
- Simplified response types avoiding DTO compilation issues
- Comprehensive error handling and logging
- Production-ready business logic integration

Remaining work:
- Create DTO classes for PlayerController/CombatController compilation
- Set up dependency injection and authentication middleware
- Integration testing for complete API layer
This commit is contained in:
matt 2025-10-19 16:07:16 -05:00
parent daa0ba8f72
commit 52cd8951fa
6 changed files with 5533 additions and 4 deletions

View File

@ -0,0 +1,903 @@
/*
* File: D:\shadowed-realms-mobile\ShadowedRealmsMobile\src\server\ShadowedRealms.API\Controllers\Kingdom\KingdomController.cs
* Created: 2025-10-19
* Last Modified: 2025-10-19
* Description: REST API controller for kingdom management operations including KvK events, democratic leadership,
* population management, and kingdom mergers.
* Last Edit Notes: Initial implementation using simplified response types to avoid DTO dependencies
*/
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using ShadowedRealms.Core.Interfaces.Services;
using System.Security.Claims;
using System.Text.Json;
namespace ShadowedRealms.API.Controllers.Kingdom
{
/// <summary>
/// REST API controller for comprehensive kingdom management operations
/// </summary>
[ApiController]
[Route("api/v1/kingdoms")]
[Authorize] // JWT authentication required for all kingdom operations
[Produces("application/json")]
public class KingdomController : ControllerBase
{
private readonly IKingdomService _kingdomService;
private readonly ILogger<KingdomController> _logger;
public KingdomController(
IKingdomService kingdomService,
ILogger<KingdomController> logger)
{
_kingdomService = kingdomService ?? throw new ArgumentNullException(nameof(kingdomService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
#region Kingdom Information
/// <summary>
/// Retrieves comprehensive kingdom information including population, leadership, and status
/// </summary>
/// <param name="kingdomId">Kingdom ID (optional - defaults to current player's kingdom)</param>
/// <returns>Complete kingdom information</returns>
[HttpGet("{kingdomId?}")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
public async Task<IActionResult> GetKingdomInfo(int? kingdomId = null)
{
try
{
var (playerId, playerKingdomId) = GetAuthenticatedPlayer();
var targetKingdomId = kingdomId ?? playerKingdomId;
var kingdomInfo = await _kingdomService.GetKingdomInfoAsync(targetKingdomId);
var response = new
{
PlayerId = playerId,
KingdomId = targetKingdomId,
KingdomInfo = kingdomInfo,
LastUpdated = DateTime.UtcNow
};
_logger.LogInformation("Kingdom info retrieved for Kingdom {KingdomId} by Player {PlayerId}",
targetKingdomId, playerId);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving kingdom information for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
return StatusCode(500, new { Message = "Failed to retrieve kingdom information", Code = "KINGDOM_INFO_ERROR" });
}
}
/// <summary>
/// Gets current kingdom population status with capacity and activity metrics
/// </summary>
/// <param name="kingdomId">Kingdom ID (optional - defaults to current player's kingdom)</param>
/// <returns>Kingdom population analysis</returns>
[HttpGet("{kingdomId?}/population")]
[ProducesResponseType(typeof(object), 200)]
public async Task<IActionResult> GetKingdomPopulation(int? kingdomId = null)
{
try
{
var (playerId, playerKingdomId) = GetAuthenticatedPlayer();
var targetKingdomId = kingdomId ?? playerKingdomId;
var populationData = await _kingdomService.MonitorKingdomPopulationAsync(targetKingdomId);
var response = new
{
PlayerId = playerId,
KingdomId = targetKingdomId,
PopulationData = populationData,
LastUpdated = DateTime.UtcNow
};
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving kingdom population for Kingdom {KingdomId}", kingdomId ?? GetAuthenticatedPlayer().KingdomId);
return StatusCode(500, new { Message = "Failed to retrieve kingdom population", Code = "POPULATION_ERROR" });
}
}
#endregion
#region KvK Events Management
/// <summary>
/// Initiates Kingdom vs Kingdom event with multi-dimensional matchmaking
/// </summary>
/// <param name="request">KvK initiation parameters</param>
/// <returns>KvK initiation result with matchmaking details</returns>
[HttpPost("kvk/initiate")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> InitiateKvKEvent([FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid KvK initiation request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var (success, kvkEventId, matchedKingdoms, eventSchedule) =
await _kingdomService.InitiateKvKEventAsync(
kingdomId,
requestDict?.ContainsKey("eventType") == true ? requestDict["eventType"].ToString() : "standard",
requestDict?.ContainsKey("matchmakingCriteria") == true ? (Dictionary<string, object>)requestDict["matchmakingCriteria"] : new()
);
if (!success)
{
return Forbid(new { Message = "KvK initiation failed - insufficient authority or invalid criteria", Code = "KVK_INITIATION_FAILED" });
}
var response = new
{
PlayerId = playerId,
KingdomId = kingdomId,
Success = success,
KvKEventId = kvkEventId,
MatchedKingdoms = matchedKingdoms,
EventSchedule = eventSchedule,
InitiationTime = DateTime.UtcNow
};
_logger.LogInformation("KvK event initiated successfully for Kingdom {KingdomId} - Event ID: {EventId}",
kingdomId, kvkEventId);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error initiating KvK event for Kingdom {KingdomId}", GetAuthenticatedPlayer().KingdomId);
return StatusCode(500, new { Message = "Failed to initiate KvK event", Code = "KVK_INITIATION_ERROR" });
}
}
/// <summary>
/// Coordinates KvK event operations with coalition support
/// </summary>
/// <param name="eventId">KvK event identifier</param>
/// <param name="request">KvK coordination parameters</param>
/// <returns>KvK coordination result</returns>
[HttpPost("kvk/{eventId}/coordinate")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
public async Task<IActionResult> CoordinateKvKEvent(string eventId, [FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid KvK coordination request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var coordinationResult = await _kingdomService.CoordinateKvKEventAsync(
kingdomId, eventId,
requestDict?.ContainsKey("coalitionSupport") == true ? (Dictionary<string, object>)requestDict["coalitionSupport"] : new(),
requestDict?.ContainsKey("strategyUpdates") == true ? (Dictionary<string, object>)requestDict["strategyUpdates"] : new()
);
var response = new
{
PlayerId = playerId,
KingdomId = kingdomId,
EventId = eventId,
CoordinationResult = coordinationResult,
CoordinationTime = DateTime.UtcNow
};
_logger.LogInformation("KvK coordination processed for Event {EventId} by Kingdom {KingdomId}",
eventId, kingdomId);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error coordinating KvK event {EventId} for Kingdom {KingdomId}",
eventId, GetAuthenticatedPlayer().KingdomId);
return StatusCode(500, new { Message = "Failed to coordinate KvK event", Code = "KVK_COORDINATION_ERROR" });
}
}
/// <summary>
/// Processes KvK event conclusion with rankings and rewards
/// </summary>
/// <param name="eventId">KvK event identifier</param>
/// <param name="request">KvK conclusion parameters</param>
/// <returns>KvK conclusion result with rankings</returns>
[HttpPost("kvk/{eventId}/conclude")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> ConcludeKvKEvent(string eventId, [FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid KvK conclusion request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var (success, finalRankings, kingdomRewards) =
await _kingdomService.ProcessKvKConclusionAsync(
eventId,
requestDict?.ContainsKey("eventResults") == true ? (Dictionary<string, object>)requestDict["eventResults"] : new()
);
if (!success)
{
return Forbid(new { Message = "KvK conclusion failed - event not ready for conclusion or insufficient authority", Code = "KVK_CONCLUSION_FAILED" });
}
var response = new
{
PlayerId = playerId,
KingdomId = kingdomId,
EventId = eventId,
Success = success,
FinalRankings = finalRankings,
KingdomRewards = kingdomRewards,
ConclusionTime = DateTime.UtcNow
};
_logger.LogInformation("KvK event concluded successfully - Event ID: {EventId}", eventId);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error concluding KvK event {EventId}", eventId);
return StatusCode(500, new { Message = "Failed to conclude KvK event", Code = "KVK_CONCLUSION_ERROR" });
}
}
/// <summary>
/// Processes KvK season conclusion with seasonal rankings and rewards
/// </summary>
/// <param name="seasonId">KvK season identifier</param>
/// <param name="request">Season conclusion parameters</param>
/// <returns>Season conclusion result</returns>
[HttpPost("kvk/season/{seasonId}/conclude")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> ConcludeKvKSeason(string seasonId, [FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid season conclusion request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var seasonResults = await _kingdomService.ProcessKvKSeasonConclusionAsync(
seasonId,
requestDict?.ContainsKey("kingdomIds") == true ?
((System.Text.Json.JsonElement)requestDict["kingdomIds"]).Deserialize<List<int>>() ?? new() :
new() { kingdomId }
);
var response = new
{
PlayerId = playerId,
KingdomId = kingdomId,
SeasonId = seasonId,
SeasonResults = seasonResults,
ConclusionTime = DateTime.UtcNow
};
_logger.LogInformation("KvK season concluded successfully - Season ID: {SeasonId}", seasonId);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error concluding KvK season {SeasonId}", seasonId);
return StatusCode(500, new { Message = "Failed to conclude KvK season", Code = "SEASON_CONCLUSION_ERROR" });
}
}
#endregion
#region Democratic Leadership
/// <summary>
/// Conducts democratic election for kingdom leadership positions
/// </summary>
/// <param name="request">Democratic election parameters</param>
/// <returns>Election results with democratic validation</returns>
[HttpPost("elections/leadership")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> ConductDemocraticElection([FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid democratic election request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var (success, electedLeaders, electionResults, votingTransparency) =
await _kingdomService.ConductDemocraticElectionAsync(
kingdomId,
requestDict?.ContainsKey("electionType") == true ? requestDict["electionType"].ToString() : "council",
requestDict?.ContainsKey("candidateIds") == true ?
((System.Text.Json.JsonElement)requestDict["candidateIds"]).Deserialize<List<int>>() ?? new() : new(),
requestDict?.ContainsKey("voterEligibility") == true ? (Dictionary<string, object>)requestDict["voterEligibility"] : new()
);
if (!success)
{
return Forbid(new { Message = "Democratic election failed - insufficient authority or election fraud detected", Code = "ELECTION_FAILED" });
}
var response = new
{
PlayerId = playerId,
KingdomId = kingdomId,
Success = success,
ElectedLeaders = electedLeaders,
ElectionResults = electionResults,
VotingTransparency = votingTransparency,
ElectionTime = DateTime.UtcNow
};
_logger.LogInformation("Democratic election completed for Kingdom {KingdomId} - Election Type: {Type}",
kingdomId, requestDict?.ContainsKey("electionType") == true ? requestDict["electionType"].ToString() : "council");
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error conducting democratic election for Kingdom {KingdomId}", GetAuthenticatedPlayer().KingdomId);
return StatusCode(500, new { Message = "Failed to conduct democratic election", Code = "DEMOCRATIC_ELECTION_ERROR" });
}
}
/// <summary>
/// Processes democratic host selection for KvK events
/// </summary>
/// <param name="request">Host selection parameters</param>
/// <returns>Host selection result with democratic validation</returns>
[HttpPost("elections/kvk-host")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> ProcessDemocraticHostSelection([FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid host selection request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var (success, selectedHostPlayerId, hostAuthorities, selectionValidation) =
await _kingdomService.ProcessDemocraticHostSelectionAsync(
kingdomId,
requestDict?.ContainsKey("kvkEventId") == true ? requestDict["kvkEventId"].ToString() : "",
requestDict?.ContainsKey("allianceVotes") == true ? (Dictionary<int, Dictionary<int, int>>)requestDict["allianceVotes"] : new(),
requestDict?.ContainsKey("selectionCriteria") == true ? (Dictionary<string, object>)requestDict["selectionCriteria"] : new()
);
if (!success)
{
return Forbid(new { Message = "Host selection failed - insufficient authority or selection fraud detected", Code = "HOST_SELECTION_FAILED" });
}
var response = new
{
PlayerId = playerId,
KingdomId = kingdomId,
Success = success,
SelectedHostPlayerId = selectedHostPlayerId,
HostAuthorities = hostAuthorities,
SelectionValidation = selectionValidation,
SelectionTime = DateTime.UtcNow
};
_logger.LogInformation("Host selection completed for Kingdom {KingdomId} - Selected Host: {HostId}",
kingdomId, selectedHostPlayerId);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing host selection for Kingdom {KingdomId}", GetAuthenticatedPlayer().KingdomId);
return StatusCode(500, new { Message = "Failed to process host selection", Code = "HOST_SELECTION_ERROR" });
}
}
/// <summary>
/// Processes democratic tax distribution with transparent allocation
/// </summary>
/// <param name="request">Tax distribution parameters</param>
/// <returns>Tax distribution result with allocation transparency</returns>
[HttpPost("tax-distribution")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> ProcessDemocraticTaxDistribution([FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid tax distribution request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var (success, distributionPlan, allianceAllocations, distributionAudit) =
await _kingdomService.ProcessDemocraticTaxDistributionAsync(
kingdomId,
requestDict?.ContainsKey("taxCollectionData") == true ? (Dictionary<string, long>)requestDict["taxCollectionData"] : new(),
requestDict?.ContainsKey("distributionCriteria") == true ? (Dictionary<string, object>)requestDict["distributionCriteria"] : new(),
requestDict?.ContainsKey("councilApproval") == true ? (Dictionary<int, bool>)requestDict["councilApproval"] : new()
);
if (!success)
{
return Forbid(new { Message = "Tax distribution failed - insufficient council approval or invalid criteria", Code = "TAX_DISTRIBUTION_FAILED" });
}
var response = new
{
PlayerId = playerId,
KingdomId = kingdomId,
Success = success,
DistributionPlan = distributionPlan,
AllianceAllocations = allianceAllocations,
DistributionAudit = distributionAudit,
DistributionTime = DateTime.UtcNow
};
_logger.LogInformation("Democratic tax distribution processed for Kingdom {KingdomId}", kingdomId);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing tax distribution for Kingdom {KingdomId}", GetAuthenticatedPlayer().KingdomId);
return StatusCode(500, new { Message = "Failed to process tax distribution", Code = "TAX_DISTRIBUTION_ERROR" });
}
}
/// <summary>
/// Manages royal council operations with democratic decision-making
/// </summary>
/// <param name="request">Royal council parameters</param>
/// <returns>Council operation result with voting records</returns>
[HttpPost("royal-council/operate")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> OperateRoyalCouncil([FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid royal council request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var (success, actionResult, councilVotes, governanceTransparency) =
await _kingdomService.OperateRoyalCouncilAsync(
kingdomId,
requestDict?.ContainsKey("councilAction") == true ? requestDict["councilAction"].ToString() : "",
requestDict?.ContainsKey("councilMembers") == true ?
((System.Text.Json.JsonElement)requestDict["councilMembers"]).Deserialize<List<int>>() ?? new() : new(),
requestDict?.ContainsKey("actionDetails") == true ? (Dictionary<string, object>)requestDict["actionDetails"] : new()
);
if (!success)
{
return Forbid(new { Message = "Royal council operation failed - insufficient authority or council rejection", Code = "COUNCIL_OPERATION_FAILED" });
}
var response = new
{
PlayerId = playerId,
KingdomId = kingdomId,
Success = success,
ActionResult = actionResult,
CouncilVotes = councilVotes,
GovernanceTransparency = governanceTransparency,
OperationTime = DateTime.UtcNow
};
_logger.LogInformation("Royal council operation processed for Kingdom {KingdomId} - Action: {Action}",
kingdomId, requestDict?.ContainsKey("councilAction") == true ? requestDict["councilAction"].ToString() : "unknown");
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error operating royal council for Kingdom {KingdomId}", GetAuthenticatedPlayer().KingdomId);
return StatusCode(500, new { Message = "Failed to operate royal council", Code = "ROYAL_COUNCIL_ERROR" });
}
}
#endregion
#region Population Management
/// <summary>
/// Monitors kingdom population with scaling recommendations
/// </summary>
/// <param name="kingdomId">Kingdom ID (optional - defaults to current player's kingdom)</param>
/// <returns>Population monitoring analysis</returns>
[HttpGet("{kingdomId?}/population/monitor")]
[ProducesResponseType(typeof(object), 200)]
public async Task<IActionResult> MonitorKingdomPopulation(int? kingdomId = null)
{
try
{
var (playerId, playerKingdomId) = GetAuthenticatedPlayer();
var targetKingdomId = kingdomId ?? playerKingdomId;
var monitoringResult = await _kingdomService.MonitorKingdomPopulationAsync(targetKingdomId);
var response = new
{
PlayerId = playerId,
KingdomId = targetKingdomId,
MonitoringResult = monitoringResult,
MonitoringTime = DateTime.UtcNow
};
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error monitoring kingdom population for Kingdom {KingdomId}",
kingdomId ?? GetAuthenticatedPlayer().KingdomId);
return StatusCode(500, new { Message = "Failed to monitor kingdom population", Code = "POPULATION_MONITORING_ERROR" });
}
}
/// <summary>
/// Creates new kingdom when population capacity is exceeded
/// </summary>
/// <param name="request">Kingdom creation parameters</param>
/// <returns>Kingdom creation result</returns>
[HttpPost("create")]
[ProducesResponseType(typeof(object), 201)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> CreateKingdom([FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid kingdom creation request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var (success, newKingdomId, migrationIncentives) =
await _kingdomService.CreateKingdomAsync(
requestDict?.ContainsKey("kingdomName") == true ? requestDict["kingdomName"].ToString() : "New Kingdom",
requestDict?.ContainsKey("initialSettings") == true ? (Dictionary<string, object>)requestDict["initialSettings"] : new()
);
if (!success)
{
return Forbid(new { Message = "Kingdom creation failed - insufficient authority or invalid settings", Code = "KINGDOM_CREATION_FAILED" });
}
var response = new
{
PlayerId = playerId,
RequestingKingdomId = kingdomId,
Success = success,
NewKingdomId = newKingdomId,
MigrationIncentives = migrationIncentives,
CreationTime = DateTime.UtcNow
};
_logger.LogInformation("Kingdom created successfully - New Kingdom ID: {NewKingdomId}, Created by Player {PlayerId}",
newKingdomId, playerId);
return CreatedAtAction(nameof(GetKingdomInfo), new { kingdomId = newKingdomId }, response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating kingdom for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
return StatusCode(500, new { Message = "Failed to create kingdom", Code = "KINGDOM_CREATION_ERROR" });
}
}
/// <summary>
/// Manages kingdom migration with incentive programs
/// </summary>
/// <param name="request">Migration management parameters</param>
/// <returns>Migration management result</returns>
[HttpPost("migration/manage")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> ManageKingdomMigration([FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid migration management request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var migrationResult = await _kingdomService.ManageMigrationIncentivesAsync(
kingdomId,
requestDict?.ContainsKey("targetKingdomIds") == true ?
((System.Text.Json.JsonElement)requestDict["targetKingdomIds"]).Deserialize<List<int>>() ?? new() : new(),
requestDict?.ContainsKey("incentivePrograms") == true ? (Dictionary<string, object>)requestDict["incentivePrograms"] : new()
);
var response = new
{
PlayerId = playerId,
KingdomId = kingdomId,
MigrationResult = migrationResult,
ManagementTime = DateTime.UtcNow
};
_logger.LogInformation("Kingdom migration managed for Kingdom {KingdomId} by Player {PlayerId}",
kingdomId, playerId);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error managing kingdom migration for Kingdom {KingdomId}", GetAuthenticatedPlayer().KingdomId);
return StatusCode(500, new { Message = "Failed to manage kingdom migration", Code = "MIGRATION_MANAGEMENT_ERROR" });
}
}
#endregion
#region Kingdom Mergers
/// <summary>
/// Initiates voluntary kingdom merger process with democratic approval
/// </summary>
/// <param name="request">Kingdom merger parameters</param>
/// <returns>Kingdom merger initiation result</returns>
[HttpPost("merger/initiate")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> InitiateKingdomMerger([FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid kingdom merger request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var (success, mergerProposalId, compatibilityAnalysis, democraticRequirements) =
await _kingdomService.InitiateKingdomMergerAsync(
kingdomId,
requestDict?.ContainsKey("targetKingdomIds") == true ?
((System.Text.Json.JsonElement)requestDict["targetKingdomIds"]).Deserialize<List<int>>() ?? new() : new(),
requestDict?.ContainsKey("mergerReasoning") == true ? requestDict["mergerReasoning"].ToString() : "",
requestDict?.ContainsKey("proposedTerms") == true ? (Dictionary<string, object>)requestDict["proposedTerms"] : new()
);
if (!success)
{
return Forbid(new { Message = "Kingdom merger initiation failed - insufficient authority or incompatible kingdoms", Code = "MERGER_INITIATION_FAILED" });
}
var response = new
{
PlayerId = playerId,
KingdomId = kingdomId,
Success = success,
MergerProposalId = mergerProposalId,
CompatibilityAnalysis = compatibilityAnalysis,
DemocraticRequirements = democraticRequirements,
InitiationTime = DateTime.UtcNow
};
_logger.LogInformation("Kingdom merger initiated for Kingdom {KingdomId} - Proposal ID: {ProposalId}",
kingdomId, mergerProposalId);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error initiating kingdom merger for Kingdom {KingdomId}", GetAuthenticatedPlayer().KingdomId);
return StatusCode(500, new { Message = "Failed to initiate kingdom merger", Code = "MERGER_INITIATION_ERROR" });
}
}
/// <summary>
/// Processes democratic approval for kingdom merger
/// </summary>
/// <param name="mergerProposalId">Merger proposal identifier</param>
/// <param name="request">Merger approval parameters</param>
/// <returns>Merger approval result with democratic validation</returns>
[HttpPost("merger/{mergerProposalId}/approve")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> ProcessMergerApproval(string mergerProposalId, [FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid merger approval request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var (success, approvalStatus, votingResults, nextSteps) =
await _kingdomService.ProcessMergerApprovalAsync(
mergerProposalId, kingdomId,
requestDict?.ContainsKey("kingdomVotes") == true ? (Dictionary<int, bool>)requestDict["kingdomVotes"] : new(),
requestDict?.ContainsKey("voterTurnout") == true ? (Dictionary<int, double>)requestDict["voterTurnout"] : new()
);
if (!success)
{
return Forbid(new { Message = "Merger approval failed - insufficient votes or approval fraud detected", Code = "MERGER_APPROVAL_FAILED" });
}
var response = new
{
PlayerId = playerId,
KingdomId = kingdomId,
MergerProposalId = mergerProposalId,
Success = success,
ApprovalStatus = approvalStatus,
VotingResults = votingResults,
NextSteps = nextSteps,
ApprovalTime = DateTime.UtcNow
};
_logger.LogInformation("Merger approval processed for Proposal {ProposalId} - Status: {Status}",
mergerProposalId, approvalStatus);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing merger approval for Proposal {ProposalId}", mergerProposalId);
return StatusCode(500, new { Message = "Failed to process merger approval", Code = "MERGER_APPROVAL_ERROR" });
}
}
/// <summary>
/// Executes approved kingdom merger with integration planning
/// </summary>
/// <param name="mergerProposalId">Merger proposal identifier</param>
/// <param name="request">Merger execution parameters</param>
/// <returns>Merger execution result</returns>
[HttpPost("merger/{mergerProposalId}/execute")]
[ProducesResponseType(typeof(object), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(403)]
public async Task<IActionResult> ExecuteKingdomMerger(string mergerProposalId, [FromBody] object request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new { Message = "Invalid merger execution request", Code = "INVALID_REQUEST" });
}
var (playerId, kingdomId) = GetAuthenticatedPlayer();
var requestDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(request.ToString() ?? "{}");
var (success, resultingKingdomId, integrationPlan, preservedBenefits) =
await _kingdomService.ExecuteKingdomMergerAsync(
mergerProposalId,
requestDict?.ContainsKey("integrationStrategy") == true ? (Dictionary<string, object>)requestDict["integrationStrategy"] : new(),
requestDict?.ContainsKey("leadershipIntegration") == true ? (Dictionary<string, object>)requestDict["leadershipIntegration"] : new()
);
if (!success)
{
return Forbid(new { Message = "Kingdom merger execution failed - merger not approved or execution error", Code = "MERGER_EXECUTION_FAILED" });
}
var response = new
{
PlayerId = playerId,
OriginKingdomId = kingdomId,
MergerProposalId = mergerProposalId,
Success = success,
ResultingKingdomId = resultingKingdomId,
IntegrationPlan = integrationPlan,
PreservedBenefits = preservedBenefits,
ExecutionTime = DateTime.UtcNow
};
_logger.LogInformation("Kingdom merger executed successfully - Proposal {ProposalId}, Resulting Kingdom: {ResultingKingdomId}",
mergerProposalId, resultingKingdomId);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error executing kingdom merger for Proposal {ProposalId}", mergerProposalId);
return StatusCode(500, new { Message = "Failed to execute kingdom merger", Code = "MERGER_EXECUTION_ERROR" });
}
}
#endregion
#region Helper Methods
/// <summary>
/// Extracts authenticated player information from JWT claims
/// </summary>
/// <returns>Player ID and Kingdom ID from authentication context</returns>
/// <exception cref="UnauthorizedAccessException">Thrown when authentication claims are invalid</exception>
private (int PlayerId, int KingdomId) GetAuthenticatedPlayer()
{
var playerIdClaim = User.FindFirst("player_id")?.Value;
var kingdomIdClaim = User.FindFirst("kingdom_id")?.Value;
if (string.IsNullOrEmpty(playerIdClaim) || string.IsNullOrEmpty(kingdomIdClaim))
{
throw new UnauthorizedAccessException("Invalid authentication claims - player or kingdom not found");
}
if (!int.TryParse(playerIdClaim, out int playerId) ||
!int.TryParse(kingdomIdClaim, out int kingdomId))
{
throw new UnauthorizedAccessException("Invalid authentication claims - unable to parse player or kingdom ID");
}
return (playerId, kingdomId);
}
#endregion
}
}

View File

@ -19,11 +19,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers\Alliance\" />
<Folder Include="Controllers\Kingdom\" />
<Folder Include="Controllers\Combat\" />
<Folder Include="Controllers\Admin\" />
<Folder Include="Controllers\Player\" />
<Folder Include="Middleware\" />
<Folder Include="Filters\" />
<Folder Include="DTOs\" />