package persistence

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"strings"

	"github.com/nexuscrm/shared/pkg/constants"
)

type layoutAuthoringSchemaRequirement struct {
	table   string
	columns []string
}

var layoutAuthoringSchemaRequirements = []layoutAuthoringSchemaRequirement{
	{
		table: constants.TableObject,
		columns: []string{
			constants.FieldID, constants.FieldAPIName, constants.FieldSysObject_ListFields,
			constants.FieldSysObject_ListFieldsCustomized, constants.FieldSysObject_IsCustomized,
			constants.FieldIsDeleted, constants.FieldLastModifiedDate,
		},
	},
	{
		table: constants.TableField,
		columns: []string{
			constants.FieldObjectID, constants.FieldID, constants.FieldAPIName, constants.FieldIsDeleted,
		},
	},
	{
		table: constants.TablePageLayout,
		columns: appendLayoutAuthoringRequiredColumns(
			constants.ColsSystemPageLayout, constants.FieldSysPageLayout_OwnerPack,
		),
	},
	{
		table: constants.TableLayoutAssignment,
		columns: appendLayoutAuthoringRequiredColumns(
			constants.ColsSystemLayoutAssignment, constants.FieldSysLayoutAssignment_OwnerPack,
		),
	},
	{table: constants.TablePageLayoutHistory, columns: constants.ColsSystemPageLayoutHistory},
	{
		table: constants.TableRecordType,
		columns: []string{
			constants.FieldID, constants.FieldSysRecordType_ObjectAPIName, constants.FieldSysRecordType_Name,
			constants.FieldSysRecordType_DeveloperName, constants.FieldSysRecordType_Description,
			constants.FieldSysRecordType_IsActive, constants.FieldSysRecordType_IsMaster,
			constants.FieldSysRecordType_BusinessProcessID, constants.FieldIsDeleted,
			constants.FieldCreatedDate, constants.FieldLastModifiedDate,
		},
	},
	{
		table: constants.TableProfile,
		columns: []string{
			constants.FieldID, constants.FieldProfile_Name, constants.FieldProfile_Description,
			constants.FieldProfile_IsSystem, constants.FieldProfile_IsActive, constants.FieldProfile_IsDeleted,
		},
	},
}

func appendLayoutAuthoringRequiredColumns(base []string, required ...string) []string {
	columns := append([]string(nil), base...)
	seen := make(map[string]struct{}, len(columns)+len(required))
	for _, column := range columns {
		seen[column] = struct{}{}
	}
	for _, column := range required {
		if _, exists := seen[column]; exists {
			continue
		}
		columns = append(columns, column)
		seen[column] = struct{}{}
	}
	return columns
}

// VerifyLayoutAuthoringSchema proves the physical read/write closure required
// by the durable Layout executor before the worker reports ready. The metadata
// and permission repositories remain the operation owners; this check only
// prevents a partially bootstrapped database from being accepted at startup.
func VerifyLayoutAuthoringSchema(ctx context.Context, db *sql.DB) error {
	if ctx == nil || db == nil {
		return errors.New("Layout authoring schema: context and database are required")
	}
	for _, requirement := range layoutAuthoringSchemaRequirements {
		quoted := make([]string, len(requirement.columns))
		for index, column := range requirement.columns {
			quoted[index] = "`" + column + "`"
		}
		query := fmt.Sprintf(
			"SELECT %s FROM `%s` WHERE 1 = 0",
			strings.Join(quoted, ", "),
			requirement.table,
		)
		rows, err := db.QueryContext(ctx, query)
		if err != nil {
			return fmt.Errorf("Layout authoring schema: inspect %s: %w", requirement.table, err)
		}
		if err := rows.Close(); err != nil {
			return fmt.Errorf("Layout authoring schema: close %s probe: %w", requirement.table, err)
		}
	}
	return nil
}
