package p.studio.lsp.services.protocol.mapping;

import org.eclipse.lsp4j.*;
import p.studio.lsp.messages.*;

import java.util.List;

public final class Lsp4jProtocolMessageMapper implements ProtocolMessageMapper {
    @Override
    public InitializeResult mapInitializeResult(final BaselineServerDescription description) {
        final ServerCapabilities capabilities = new ServerCapabilities();

        final TextDocumentSyncOptions syncOptions = new TextDocumentSyncOptions();
        syncOptions.setOpenClose(true);
        syncOptions.setChange(TextDocumentSyncKind.Full);

        final SaveOptions saveOptions = new SaveOptions();
        saveOptions.setIncludeText(true);
        syncOptions.setSave(saveOptions);

        capabilities.setTextDocumentSync(syncOptions);
        capabilities.setHoverProvider(description.hoverSupported());

        final InitializeResult result = new InitializeResult(capabilities);
        final ServerInfo serverInfo = new ServerInfo();
        serverInfo.setName(description.name());
        serverInfo.setVersion(description.version());
        result.setServerInfo(serverInfo);
        return result;
    }

    @Override
    public PublishDiagnosticsParams mapDiagnostics(
            final String uri,
            final BaselineDocumentAnalysis analysis) {
        return new PublishDiagnosticsParams(uri, analysis.issues().stream().map(this::mapDiagnostic).toList());
    }

    @Override
    public PublishDiagnosticsParams emptyDiagnostics(final String uri) {
        return new PublishDiagnosticsParams(uri, List.of());
    }

    @Override
    public Hover mapHover(final BaselineHover hover) {
        final MarkupContent content = new MarkupContent();
        content.setKind(MarkupKind.MARKDOWN);
        content.setValue(hover.markdown());

        final Hover result = new Hover();
        result.setContents(content);
        return result;
    }

    @Override
    public MessageParams mapInfoMessage(final String message) {
        return new MessageParams(MessageType.Info, message);
    }

    @Override
    public MessageParams mapErrorMessage(final String message) {
        return new MessageParams(MessageType.Error, message);
    }

    @Override
    public MessageParams mapWarningMessage(String message) {
        return new MessageParams(MessageType.Warning, message);
    }

    private Diagnostic mapDiagnostic(final BaselineDocumentIssue issue) {
        final Diagnostic diagnostic = new Diagnostic();
        diagnostic.setRange(new Range(
                new Position(issue.startLine(), issue.startCharacter()),
                new Position(issue.endLine(), issue.endCharacter())));
        diagnostic.setSeverity(mapSeverity(issue.severity()));
        diagnostic.setSource(issue.source());
        diagnostic.setMessage(issue.message());
        return diagnostic;
    }


    private DiagnosticSeverity mapSeverity(final BaselineIssueSeverity severity) {
        return switch (severity) {
            case INFORMATION -> DiagnosticSeverity.Information;
            case WARNING -> DiagnosticSeverity.Warning;
            case ERROR -> DiagnosticSeverity.Error;
        };
    }
}
