package httpapi

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/dtoro/oikos/internal/adapters/postgres/sqlcgen"
	"github.com/dtoro/oikos/internal/httpapi/gen"
)

func (s *Server) GetOntology(ctx context.Context, req gen.GetOntologyRequestObject) (gen.GetOntologyResponseObject, error) {
	resp := gen.GetOntology200JSONResponse{
		EntityTypes:       []gen.EntityType{},
		RelationshipTypes: []gen.RelationshipType{},
		Lifecycles:        []gen.LifecycleDef{},
	}

	q := sqlcgen.New(s.pool)

	etRows, err := q.ListEntityTypes(ctx)
	if err != nil {
		return nil, err
	}
	for _, et := range etRows {
		schemaVersion := int(et.SchemaVersion)
		var schema *map[string]any
		if len(et.AttributeSchema) > 0 {
			var s map[string]any
			if json.Unmarshal(et.AttributeSchema, &s) == nil && s != nil {
				schema = &s
			}
		}
		resp.EntityTypes = append(resp.EntityTypes, gen.EntityType{
			Name:            et.Name,
			ParentType:      et.ParentType,
			IsAbstract:      et.IsAbstract,
			Domain:          et.Domain,
			Layer:           gen.EntityTypeLayer(et.Layer),
			Description:     et.Description,
			LifecycleId:     et.LifecycleID,
			SchemaVersion:   &schemaVersion,
			AttributeSchema: schema,
			Status:          gen.EntityTypeStatus(et.Status),
		})
	}

	rtRows, err := q.ListRelationshipTypes(ctx)
	if err != nil {
		return nil, err
	}
	for _, rt := range rtRows {
		resp.RelationshipTypes = append(resp.RelationshipTypes, gen.RelationshipType{
			Name:        rt.Name,
			Inverse:     rt.Inverse,
			SourceType:  rt.SourceType,
			TargetType:  rt.TargetType,
			Cardinality: gen.RelationshipTypeCardinality(rt.Cardinality),
			Description: rt.Description,
		})
	}

	lcRows, err := q.ListLifecycleDefs(ctx)
	if err != nil {
		return nil, err
	}
	for _, lc := range lcRows {
		terminal := lc.TerminalStates
		var transitions map[string]any
		if err := json.Unmarshal(lc.Transitions, &transitions); err != nil {
			return nil, fmt.Errorf("lifecycle %s transitions: %w", lc.ID, err)
		}
		resp.Lifecycles = append(resp.Lifecycles, gen.LifecycleDef{
			Id:             lc.ID,
			States:         lc.States,
			DefaultState:   lc.DefaultState,
			TerminalStates: &terminal,
			Transitions:    transitions,
		})
	}

	return resp, nil
}