using System.Text.Json;
using System.Text.Json.Serialization;

namespace PlotLine.Models;

public sealed class PlotLineImportPackage
{
    public string? PackageVersion { get; set; }
    public string? Source { get; set; }
    public string? CreatedBy { get; set; }
    public string? CreatedDate { get; set; }
    public string? Description { get; set; }
    public ImportProjectDto Project { get; set; } = new();
    public ImportAliasesDto Aliases { get; set; } = new();
    public List<ImportCharacterDto> Characters { get; set; } = [];
    public List<ImportLocationDto> Locations { get; set; } = [];
    public List<ImportPlotLineDto> PlotLines { get; set; } = [];
    public List<ImportStoryAssetDto> StoryAssets { get; set; } = [];
    public List<ImportSceneDependencyDto> SceneDependencies { get; set; } = [];
    public List<ImportBookDto> Books { get; set; } = [];

    [JsonExtensionData]
    public Dictionary<string, object>? ExtensionData { get; set; }
}

public sealed class ImportAliasesDto
{
    public Dictionary<string, string> Characters { get; set; } = new(StringComparer.OrdinalIgnoreCase);
    public Dictionary<string, string> Locations { get; set; } = new(StringComparer.OrdinalIgnoreCase);
}

public sealed class ProjectBackupRelationshipImportLookups
{
    public IReadOnlyList<ProjectBackupLookupRow> RevisionStatuses { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> TimeModes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> DurationUnits { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> TimeConfidences { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> LocationTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> LocationRelationshipTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> PlotLineTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> PlotImportance { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> ThreadTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> ThreadStatuses { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> ThreadEventTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> PlotEventTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> AssetKinds { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> AssetStates { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> AssetEventTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> AssetDependencyTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> AssetCustodyEventTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> CustodyRoles { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> CharacterRoleTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> PresenceTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> KnowledgeStates { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> SceneDependencyTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> SceneNoteTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> SceneAttachmentTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> ScenePurposeTypes { get; init; } = [];
    public IReadOnlyList<ProjectBackupLookupRow> SceneMetricTypes { get; init; } = [];
    public IReadOnlyList<RelationshipType> RelationshipTypes { get; init; } = [];
    public IReadOnlyList<RelationshipState> RelationshipStates { get; init; } = [];
}

public sealed class ProjectBackupLookupRow
{
    public int LookupID { get; set; }
    public string LookupName { get; set; } = string.Empty;
}

public sealed class ProjectBackupRelationshipImportDiagnostics
{
    public int CharacterCount { get; set; }
    public int RelationshipCount { get; set; }
    public int RelationshipEventCount { get; set; }
    public int MapRelationshipCount { get; set; }
    public int MissingSourceCharacterCount { get; set; }
    public int MissingTargetCharacterCount { get; set; }
    public int MissingRelationshipTypeCount { get; set; }
    public int MissingInitialStateCount { get; set; }
    public int MissingEventRelationshipCount { get; set; }
    public int MissingEventSceneCount { get; set; }
    public int MissingEventStateCount { get; set; }
    public int ArchivedRelationshipCount { get; set; }
    public int ArchivedCharacterEndpointCount { get; set; }
}

public sealed class ImportProjectDto
{
    public string Title { get; set; } = string.Empty;
    public string? Description { get; set; }
    public string? Notes { get; set; }
}

public sealed class ImportBookDto
{
    public string Title { get; set; } = string.Empty;
    public string? Subtitle { get; set; }
    public int SeriesOrder { get; set; }
    public bool DependsOnPreviousBook { get; set; }
    public string? Description { get; set; }
    public string? Notes { get; set; }
    public List<ImportChapterDto> Chapters { get; set; } = [];
}

public sealed class ImportCharacterDto
{
    public string Name { get; set; } = string.Empty;
    public string? DisplayName { get; set; }
    public string? ShortName { get; set; }
    public string? Role { get; set; }
    [JsonConverter(typeof(ImportImportanceJsonConverter))]
    public int? Importance { get; set; }
    public string? Description { get; set; }
    public string? Notes { get; set; }
}

public sealed class ImportLocationDto
{
    public string Name { get; set; } = string.Empty;
    public string? DisplayName { get; set; }
    public string? Type { get; set; }
    public string? ParentLocationName { get; set; }
    public string? Description { get; set; }
    public string? Notes { get; set; }
}

public sealed class ImportPlotLineDto
{
    public string Name { get; set; } = string.Empty;
    public string? DisplayName { get; set; }
    public string? Type { get; set; }
    public int? Importance { get; set; }
    public string? Description { get; set; }
    public string? Notes { get; set; }
    public List<ImportPlotThreadDto> Threads { get; set; } = [];
}

public sealed class ImportPlotThreadDto
{
    public string Name { get; set; } = string.Empty;
    public string? DisplayName { get; set; }
    public string? Type { get; set; }
    public string? Status { get; set; }
    public int? Importance { get; set; }
    public string? Description { get; set; }
    public string? Notes { get; set; }
    public List<ImportThreadEventDto> Events { get; set; } = [];
}

public sealed class ImportThreadEventDto
{
    public string? SceneRef { get; set; }
    public int? BookOrder { get; set; }
    public int? ChapterOrder { get; set; }
    public int? SceneOrder { get; set; }
    public string? Title { get; set; }
    public string? EventType { get; set; }
    public string? Summary { get; set; }
    public string? Impact { get; set; }
    public int? Importance { get; set; }
    public string? Notes { get; set; }
}

public sealed class ImportStoryAssetDto
{
    public string Name { get; set; } = string.Empty;
    public string? DisplayName { get; set; }
    public string? Type { get; set; }
    public int? Importance { get; set; }
    public string? Description { get; set; }
    public string? Notes { get; set; }
    public string? InitialOwnerCharacterName { get; set; }
    public string? InitialLocationName { get; set; }
    public List<ImportAssetStateDto> States { get; set; } = [];
    public List<ImportAssetEventDto> Events { get; set; } = [];
}

public sealed class ImportAssetStateDto
{
    public string? SceneRef { get; set; }
    public int? BookOrder { get; set; }
    public int? ChapterOrder { get; set; }
    public int? SceneOrder { get; set; }
    public string? StateName { get; set; }
    public string? Description { get; set; }
    public string? Notes { get; set; }
}

public sealed class ImportAssetEventDto
{
    public string? SceneRef { get; set; }
    public int? BookOrder { get; set; }
    public int? ChapterOrder { get; set; }
    public int? SceneOrder { get; set; }
    public string? EventType { get; set; }
    public string? Title { get; set; }
    public string? Summary { get; set; }
    public string? CharacterName { get; set; }
    public string? LocationName { get; set; }
    public string? Notes { get; set; }
}

public sealed class ImportSceneDependencyDto
{
    public ImportSceneReferenceDto? FromScene { get; set; }
    public ImportSceneReferenceDto? ToScene { get; set; }
    public string? DependencyType { get; set; }
    public string? Strength { get; set; }
    public string? Description { get; set; }
    public string? Notes { get; set; }
}

public sealed class ImportSceneReferenceDto
{
    public string? SceneRef { get; set; }
    public int? BookOrder { get; set; }
    public int? ChapterOrder { get; set; }
    public int? SceneOrder { get; set; }
}

public sealed class ImportChapterDto
{
    public decimal ChapterNumber { get; set; }
    public string Title { get; set; } = string.Empty;
    public int Order { get; set; }
    public string? Summary { get; set; }
    public string? Notes { get; set; }
    public List<ImportSceneDto> Scenes { get; set; } = [];
}

public sealed class ImportSceneDto
{
    public decimal SceneNumber { get; set; }
    public string Title { get; set; } = string.Empty;
    public int Order { get; set; }
    public string? Summary { get; set; }
    public string? PovCharacterName { get; set; }
    public string? LocationName { get; set; }
    public string? DateTimeText { get; set; }
    public string? PurposeText { get; set; }
    public string? OutcomeText { get; set; }
    public string? Notes { get; set; }
    public List<ImportSceneCharacterDto> SceneCharacters { get; set; } = [];
}

public sealed class ImportSceneCharacterDto
{
    public string CharacterName { get; set; } = string.Empty;
    public string? RoleInScene { get; set; }
    public int? Importance { get; set; }
    public string? Notes { get; set; }
}

public sealed class ImportValidationResult
{
    public bool IsValid => Errors.Count == 0;
    public List<string> Errors { get; } = [];
    public List<string> Warnings { get; } = [];
    public List<string> AutoCorrections { get; } = [];
    public List<string> SkippedItems { get; } = [];
    public List<string> UnresolvedReferences { get; } = [];
}

public sealed class ImportPreview
{
    public PlotLineImportPackage? Package { get; init; }
    public ImportValidationResult Validation { get; init; } = new();
    public bool HasDuplicateProjectTitle { get; init; }
    public string? DuplicateImportProjectTitle { get; init; }
    public IReadOnlyList<ImportBookPreview> BookPreviews { get; init; } = [];
    public IReadOnlyList<string> UnmatchedPovNames { get; init; } = [];
    public IReadOnlyList<string> UnmatchedLocationNames { get; init; } = [];
    public IReadOnlyList<string> UnmatchedSceneCharacterNames { get; init; } = [];
    public IReadOnlyList<string> UnresolvedThreadEventReferences { get; init; } = [];
    public IReadOnlyList<string> UnresolvedAssetReferences { get; init; } = [];
    public IReadOnlyList<string> UnmatchedAssetOwnerNames { get; init; } = [];
    public IReadOnlyList<string> UnmatchedAssetLocationNames { get; init; } = [];
    public IReadOnlyList<string> UnresolvedSceneDependencyReferences { get; init; } = [];
    public IReadOnlyList<string> AliasWarnings { get; init; } = [];
    public IReadOnlyList<string> AutoCorrections { get; init; } = [];
    public IReadOnlyList<string> SkippedItems { get; init; } = [];
    public int ErrorCount => Validation.Errors.Count;
    public int WarningCount => Validation.Warnings.Count;
    public int AutoCorrectionCount => AutoCorrections.Count + Validation.AutoCorrections.Count;
    public int SkippedItemCount => SkippedItems.Count + Validation.SkippedItems.Count;
    public int UnresolvedReferenceCount => UnresolvedThreadEventReferences.Count + UnresolvedAssetReferences.Count + UnresolvedSceneDependencyReferences.Count;
    public int BookCount => Package?.Books.Count ?? 0;
    public int CharacterCount => Package?.Characters.Count ?? 0;
    public int LocationCount => Package?.Locations.Count ?? 0;
    public int PlotLineCount => Package?.PlotLines.Count ?? 0;
    public int PlotThreadCount => Package?.PlotLines.Sum(plotLine => plotLine.Threads.Count) ?? 0;
    public int ThreadEventCount => Package?.PlotLines.Sum(plotLine => plotLine.Threads.Sum(thread => thread.Events.Count)) ?? 0;
    public int ResolvedThreadEventCount => Math.Max(0, ThreadEventCount - UnresolvedThreadEventReferences.Count);
    public int StoryAssetCount => Package?.StoryAssets.Count ?? 0;
    public int AssetStateCount => Package?.StoryAssets.Sum(asset => asset.States.Count) ?? 0;
    public int AssetEventCount => Package?.StoryAssets.Sum(asset => asset.Events.Count) ?? 0;
    public int AssetCustodyCount => Package?.StoryAssets.Count(asset => !string.IsNullOrWhiteSpace(asset.InitialOwnerCharacterName)) ?? 0;
    public int ResolvedAssetStateCount => Math.Max(0, AssetStateCount - UnresolvedAssetReferences.Count(x => x.Contains("state", StringComparison.OrdinalIgnoreCase)));
    public int ResolvedAssetEventCount => Math.Max(0, AssetEventCount - UnresolvedAssetReferences.Count(x => x.Contains("event", StringComparison.OrdinalIgnoreCase)));
    public int ResolvedAssetCustodyCount => Math.Max(0, AssetCustodyCount - Package?.StoryAssets.Count(asset => !string.IsNullOrWhiteSpace(asset.InitialOwnerCharacterName) && UnmatchedAssetOwnerNames.Contains(asset.InitialOwnerCharacterName.Trim(), StringComparer.OrdinalIgnoreCase)) ?? 0);
    public int SceneDependencyCount => Package?.SceneDependencies.Count ?? 0;
    public int ResolvedSceneDependencyCount => Math.Max(0, SceneDependencyCount - UnresolvedSceneDependencyReferences.Count);
    public int ChapterCount => Package?.Books.Sum(book => book.Chapters.Count) ?? 0;
    public int SceneCount => Package?.Books.Sum(book => book.Chapters.Sum(chapter => chapter.Scenes.Count)) ?? 0;
    public int SceneCharacterAppearanceCount => Package?.Books.Sum(book => book.Chapters.Sum(chapter => chapter.Scenes.Sum(scene => scene.SceneCharacters.Count + AutoPovAppearanceCount(scene)))) ?? 0;

    private static int AutoPovAppearanceCount(ImportSceneDto scene)
        => !string.IsNullOrWhiteSpace(scene.PovCharacterName)
           && scene.SceneCharacters.All(x => !string.Equals(x.CharacterName?.Trim(), scene.PovCharacterName.Trim(), StringComparison.OrdinalIgnoreCase))
            ? 1
            : 0;
}

public sealed class ImportBookPreview
{
    public ImportBookDto Book { get; init; } = new();
    public int ChapterCount => Book.Chapters.Count;
    public int SceneCount => Book.Chapters.Sum(chapter => chapter.Scenes.Count);
    public IReadOnlyList<ImportChapterPreview> ChapterPreviews { get; init; } = [];
}

public sealed class ImportChapterPreview
{
    public ImportChapterDto Chapter { get; init; } = new();
    public int SceneCount => Chapter.Scenes.Count;
}

public sealed record ImportResult
{
    public bool Succeeded { get; init; }
    public int? ProjectID { get; init; }
    public string ProjectName { get; init; } = string.Empty;
    public int BooksCreated { get; init; }
    public int ChaptersCreated { get; init; }
    public int ScenesCreated { get; init; }
    public int CharactersCreated { get; init; }
    public int LocationsCreated { get; init; }
    public int SceneCharacterAppearancesCreated { get; init; }
    public int PlotLinesCreated { get; init; }
    public int PlotThreadsCreated { get; init; }
    public int ThreadEventsCreated { get; init; }
    public int StoryAssetsCreated { get; init; }
    public int AssetStatesCreated { get; init; }
    public int AssetEventsCreated { get; init; }
    public int AssetCustodyEventsCreated { get; init; }
    public int SceneDependenciesCreated { get; init; }
    public bool IsDryRun { get; init; }
    public int ErrorCount { get; init; }
    public int WarningCount { get; init; }
    public int AutoCorrectionCount { get; init; }
    public int SkippedItemCount { get; init; }
    public int UnresolvedReferenceCount { get; init; }
    public IReadOnlyList<string> AutoCorrections { get; init; } = [];
    public IReadOnlyList<string> SkippedOptionalFields { get; init; } = [];
    public IReadOnlyList<string> UnresolvedWarnings { get; init; } = [];
    public string? TechnicalDetail { get; init; }
    public string Message { get; init; } = string.Empty;
}

public sealed class ImportImportanceJsonConverter : JsonConverter<int?>
{
    public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.Null)
        {
            return null;
        }

        if (reader.TokenType == JsonTokenType.Number && reader.TryGetInt32(out var numeric))
        {
            return Math.Clamp(numeric, 1, 10);
        }

        if (reader.TokenType != JsonTokenType.String)
        {
            return null;
        }

        var text = reader.GetString()?.Trim();
        if (string.IsNullOrWhiteSpace(text))
        {
            return null;
        }

        if (int.TryParse(text, out var parsed))
        {
            return Math.Clamp(parsed, 1, 10);
        }

        var normalized = text.ToLowerInvariant();
        if (normalized.Contains("major") || normalized.Contains("main") || normalized.Contains("protagonist"))
        {
            return 10;
        }

        if (normalized.Contains("support") || normalized.Contains("secondary"))
        {
            return 6;
        }

        if (normalized.Contains("minor") || normalized.Contains("background") || normalized.Contains("cameo"))
        {
            return 2;
        }

        return null;
    }

    public override void Write(Utf8JsonWriter writer, int? value, JsonSerializerOptions options)
    {
        if (value.HasValue)
        {
            writer.WriteNumberValue(value.Value);
        }
        else
        {
            writer.WriteNullValue();
        }
    }
}
