package com.salpa.subject.mapper;

import com.alibaba.fastjson2.JSON;
import com.salpa.subject.domain.*;
import com.salpa.subject.domain.diff.*;
import com.salpa.subject.domain.diff.data.DiffType;
import net.sourceforge.plantuml.json.JsonObject;
import org.mapstruct.Mapper;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Mapper(componentModel = "spring")
public interface DocumentDiffConverter {

    default DatabaseDocDiff of(MonitorDatabaseDocument databaseDocument,
                               List<MonitorTableDocument> tables,
                               List<MonitorTableColumnDocument> columns,
                               List<MonitorTableIndexDocument> indexes,
                               List<MonitorTableTriggerDocument> triggers,
                               List<MonitorTableForeignKeyDocument> foreignKeys) {
        List<TableDocDiff> tableDocDiffList = of(tables, columns, indexes, triggers, foreignKeys);
        return of(databaseDocument, tableDocDiffList);
    }

    default List<TableDocDiff> of(List<MonitorTableDocument> tables,
                                  List<MonitorTableColumnDocument> columns,
                                  List<MonitorTableIndexDocument> indexes,
                                  List<MonitorTableTriggerDocument> triggers,
                                  List<MonitorTableForeignKeyDocument> foreignKeys) {
        var columnGroupByTableId = groupBy(columns, MonitorTableColumnDocument::getTableDocumentId);
        var indexGroupByTableId = groupBy(indexes, MonitorTableIndexDocument::getTableDocumentId);
        var triggerGroupByTableId = groupBy(triggers, MonitorTableTriggerDocument::getTableDocumentId);
        var fkGroupByTableId = groupBy(foreignKeys, MonitorTableForeignKeyDocument::getTableDocumentId);
        return tables.stream()
                .map(table -> {
                    Integer id = table.getId();
                    var tableCols = columnGroupByTableId.getOrDefault(id, Collections.emptyList());
                    var tableIndexes = indexGroupByTableId.getOrDefault(id, Collections.emptyList());
                    var tableTriggers = triggerGroupByTableId.getOrDefault(id, Collections.emptyList());
                    var tableForeignKeys = fkGroupByTableId.getOrDefault(id, Collections.emptyList());
                    return of(table, tableCols, tableIndexes, tableTriggers, tableForeignKeys);
                })
                .collect(Collectors.toList());
    }

    default DatabaseDocDiff of(MonitorDatabaseDocument databaseDocument, List<TableDocDiff> tables) {
        DatabaseDocDiff databaseDocDiff = new DatabaseDocDiff();
        databaseDocDiff.setTables(tables);
        databaseDocDiff.setId(databaseDocument.getId());
        databaseDocDiff.setProjectId(databaseDocument.getProjectId());
        databaseDocDiff.setProductVersion(databaseDocument.getProductVersion());
        databaseDocDiff.setProductName(databaseDocument.getProductName());
        databaseDocDiff.setDatabaseName(databaseDocument.getDatabaseName());
        databaseDocDiff.setSchemaName(databaseDocument.getSchemaName());
        databaseDocDiff.setVersion(databaseDocument.getDocumentVersion());
        databaseDocDiff.setCreateAt(databaseDocument.getCreateAt());
        databaseDocDiff.setUpdateAt(databaseDocument.getUpdateAt());
        return databaseDocDiff;
    }

    default TableDocDiff of(MonitorTableDocument table,
                    List<MonitorTableColumnDocument> columns,
                    List<MonitorTableIndexDocument> indexes,
                    List<MonitorTableTriggerDocument> triggers,
                    List<MonitorTableForeignKeyDocument> foreignKeys) {
        /*column*/
        List<ColumnDocDiff> columns1 = new ArrayList<>();
        for (MonitorTableColumnDocument column : columns) {
            ColumnDocDiff columnDocDiff = new ColumnDocDiff();
            columnDocDiff.setId(column.getId());
            columnDocDiff.setType(column.getType());
            columnDocDiff.setTableDocumentId(column.getTableDocumentId());
            columnDocDiff.setSize(column.getSize());
            columnDocDiff.setNullable(column.getNullable());
            columnDocDiff.setName(column.getName());
            columnDocDiff.setIsPrimaryKey(column.getPrimaryKey());
            columnDocDiff.setDefaultValue(column.getDefaultValue());
            columnDocDiff.setDecimalDigits(column.getDecimalDigits());
            columnDocDiff.setDataType(column.getDataType());
            columnDocDiff.setDatabaseDocumentId(column.getDatabaseDocumentId());
            columnDocDiff.setComment(column.getComment());
            columnDocDiff.setAutoIncrement(column.getAutoIncrement());
            columnDocDiff.setCreateAt(column.getCreateAt());
            columns1.add(columnDocDiff);
        }
        /*index*/
        List<IndexDocDiff> indexes1 = new ArrayList<>();
        for (MonitorTableIndexDocument index : indexes) {
            IndexDocDiff indexDocDiff = new IndexDocDiff();
            indexDocDiff.setId(index.getId());
            indexDocDiff.setName(index.getName());
            indexDocDiff.setTableDocumentId(index.getTableDocumentId());
            indexDocDiff.setDatabaseDocumentId(index.getDatabaseDocumentId());
            indexDocDiff.setIsUnique(index.getUnique());
            indexDocDiff.setColumnNameArray(index.getColumnNameArray());
            indexDocDiff.setCreateAt(index.getCreateAt());
            indexes1.add(indexDocDiff);
        }
        /*triggers*/
        List<TriggerDocDiff> triggers1 = new ArrayList<>();
        for (MonitorTableTriggerDocument trigger : triggers) {
            TriggerDocDiff triggerDocDiff = new TriggerDocDiff();
            triggerDocDiff.setId(trigger.getId());
            triggerDocDiff.setName(trigger.getName());
            triggerDocDiff.setTableDocumentId(trigger.getTableDocumentId());
            triggerDocDiff.setDatabaseDocumentId(trigger.getDatabaseDocumentId());
            triggerDocDiff.setTiming(trigger.getTiming());
            triggerDocDiff.setManipulation(trigger.getManipulation());
            triggerDocDiff.setStatement(trigger.getStatement());
            triggerDocDiff.setTriggerCreateAt(trigger.getTriggerCreateAt());
            triggerDocDiff.setCreateAt(trigger.getCreateAt());
            triggers1.add(triggerDocDiff);
        }
        /*foreignKey*/
        List<ForeignKeyDocDiff> foreignKeys1 = new ArrayList<>();
        for (MonitorTableForeignKeyDocument foreignKey : foreignKeys) {
            ForeignKeyDocDiff foreignKeyDocDiff = new ForeignKeyDocDiff();
            foreignKeyDocDiff.setId(foreignKey.getId());
            foreignKeyDocDiff.setKeySeq(foreignKey.getKeySeq());
            foreignKeyDocDiff.setFkName(foreignKey.getFkName());
            foreignKeyDocDiff.setFkTableName(foreignKey.getFkTableName());
            foreignKeyDocDiff.setFkColumnName(foreignKey.getFkColumnName());
            foreignKeyDocDiff.setPkName(foreignKey.getPkName());
            foreignKeyDocDiff.setPkTableName(foreignKey.getPkTableName());
            foreignKeyDocDiff.setPkColumnName(foreignKey.getPkColumnName());
            foreignKeyDocDiff.setTableDocumentId(foreignKey.getTableDocumentId());
            foreignKeyDocDiff.setDatabaseDocumentId(foreignKey.getDatabaseDocumentId());
            foreignKeyDocDiff.setDeleteRule(foreignKey.getDeleteRule());
            foreignKeyDocDiff.setUpdateRule(foreignKey.getUpdateRule());
            foreignKeyDocDiff.setCreateAt(foreignKey.getCreateAt());
            foreignKeys1.add(foreignKeyDocDiff);
        }
        return TableDocDiff.builder()
                .id(table.getId())
                .name(table.getName())
                .comment(table.getComment())
                .type(table.getType())
                .createAt(table.getCreateAt())
                .columns(columns1)
                .indexes(indexes1)
                .triggers(triggers1)
                .foreignKeys(foreignKeys1)
                .build();
    }

    ColumnDocDiff of(MonitorTableColumnDocument pojo);

    IndexDocDiff of(MonitorTableIndexDocument pojo);

    TriggerDocDiff of(MonitorTableTriggerDocument pojo);

    ForeignKeyDocDiff of(MonitorTableForeignKeyDocument pojo);

    default <R> Map<Integer, List<R>> groupBy(List<R> content, Function<R, Integer> idMapping) {
        return content.stream()
                .collect(Collectors.groupingBy(idMapping));
    }
}
