package persistence

import (
	"database/sql"
	"encoding/json"
	"time"

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

func (r *MetadataRepository) scanApp(row Scannable) (*models.AppConfig, error) {
	var app models.AppConfig
	var name string
	var description, namespacePrefix, icon, color, navItems, utilityItems, assignedProfiles sql.NullString
	// ColsSystemApp: ID, Name, Label, Description, NamespacePrefix, Icon, Color, NavigationItems, UtilityItems, AssignedProfiles, IsDefault, CreatedDate, LastModifiedDate
	var createdDateVal, lastModifiedDateVal interface{}

	if err := row.Scan(&app.ID, &name, &app.Label, &description, &namespacePrefix, &icon, &color, &navItems, &utilityItems, &assignedProfiles, &app.IsDefault, &createdDateVal, &lastModifiedDateVal); err != nil {
		return nil, err
	}

	if description.Valid {
		app.Description = description.String
	}
	if icon.Valid {
		app.Icon = icon.String
	}
	if color.Valid {
		app.Color = color.String
	}

	if navItems.Valid {
		r.unmarshalJSON(navItems.String, &app.NavigationItems)
	}
	if utilityItems.Valid {
		r.unmarshalJSON(utilityItems.String, &app.UtilityItems)
	}
	if assignedProfiles.Valid {
		r.unmarshalJSON(assignedProfiles.String, &app.AssignedProfiles)
	}

	app.CreatedDate = parseTime(createdDateVal)
	app.LastModifiedDate = parseTime(lastModifiedDateVal)

	return &app, nil
}

func parseTime(val interface{}) time.Time {
	if val == nil {
		return time.Time{}
	}
	switch v := val.(type) {
	case time.Time:
		return v
	case []uint8:
		str := string(v)
		if t, err := time.Parse("2006-01-02 15:04:05", str); err == nil {
			return t
		}
		if t, err := time.Parse(time.RFC3339, str); err == nil {
			return t
		}
	}
	return time.Time{}
}

func (r *MetadataRepository) scanLayout(row Scannable) (*models.PageLayout, error) {
	var id, objectAPIName, layoutName, configJSON string
	var typeVal, sourceVal sql.NullString
	var isDefault, isDeleted, isCustomized bool
	var layoutVersion, generationVersion int
	var createdDateVal, lastModifiedDateVal interface{}

	if err := row.Scan(&id, &objectAPIName, &layoutName, &typeVal, &isDefault, &isDeleted, &configJSON, &createdDateVal, &lastModifiedDateVal, &isCustomized, &layoutVersion, &sourceVal, &generationVersion); err != nil {
		return nil, err
	}

	var layout models.PageLayout
	if err := json.Unmarshal([]byte(configJSON), &layout); err != nil {
		return nil, err
	}
	layout.ID = id
	layout.ObjectAPIName = objectAPIName
	layout.LayoutName = layoutName
	layout.IsDefault = isDefault
	layout.IsDeleted = isDeleted
	layout.IsCustomized = isCustomized
	layout.LayoutVersion = layoutVersion
	if sourceVal.Valid && sourceVal.String != "" {
		layout.Source = sourceVal.String
	} else {
		layout.Source = "auto_generated" // default for rows predating the migration
	}
	layout.GenerationVersion = generationVersion
	if typeVal.Valid {
		layout.Type = typeVal.String
	}
	layout.CreatedDate = parseTime(createdDateVal)
	layout.LastModifiedDate = parseTime(lastModifiedDateVal)
	return &layout, nil
}

func (r *MetadataRepository) scanDashboard(row Scannable) (*models.DashboardConfig, error) {
	var db models.DashboardConfig
	var developerName, description, folderID, layoutType, filterMode, layoutMode, dateRangeType sql.NullString
	var dashboardType, runningUserId sql.NullString
	var startDate, endDate, createdDate, lastModifiedDate sql.NullTime
	var isDeleted bool
	// ColsDashboard: ID, Name, DeveloperName, Description, FolderID, LayoutType, FilterMode, LayoutMode, StartDate, EndDate, DateRangeType, DashboardType, RunningUserId, IsDeleted, CreatedDate, LastModifiedDate

	if err := row.Scan(&db.ID, &db.Label, &developerName, &description, &folderID, &layoutType, &filterMode, &layoutMode, &startDate, &endDate, &dateRangeType, &dashboardType, &runningUserId, &isDeleted, &createdDate, &lastModifiedDate); err != nil {
		return nil, err
	}

	if description.Valid {
		db.Description = &description.String
	}
	if developerName.Valid {
		db.DeveloperName = developerName.String
	}
	if layoutType.Valid {
		db.Layout = layoutType.String
	}

	// Widgets are now managed via DashboardComponent, not embedded JSON.
	// db.Widgets = []models.WidgetConfig{}

	if filterMode.Valid {
		db.FilterMode = filterMode.String
	}
	if layoutMode.Valid {
		db.LayoutMode = layoutMode.String
	}
	if startDate.Valid {
		s := startDate.Time.Format("2006-01-02")
		db.StartDate = &s
	}
	if endDate.Valid {
		s := endDate.Time.Format("2006-01-02")
		db.EndDate = &s
	}
	if dateRangeType.Valid {
		db.DateRangeType = dateRangeType.String
	}
	if dashboardType.Valid {
		db.DashboardType = dashboardType.String
	}
	if runningUserId.Valid {
		db.RunningUserId = runningUserId.String
	}
	return &db, nil
}

func (r *MetadataRepository) scanListView(row Scannable) (*models.ListView, error) {
	var view models.ListView
	var filterExpr, fieldsJSON sql.NullString
	// ColsSystemListView: ID, ObjectAPIName, Label, FilterExpr, Fields, CreatedDate, LastModifiedDate
	var createdDateVal, lastModifiedDateVal interface{}

	if err := row.Scan(&view.ID, &view.ObjectAPIName, &view.Label, &filterExpr, &fieldsJSON, &createdDateVal, &lastModifiedDateVal); err != nil {
		return nil, err
	}
	if filterExpr.Valid {
		view.FilterExpr = filterExpr.String
	}
	if fieldsJSON.Valid {
		r.unmarshalJSON(fieldsJSON.String, &view.Fields)
	}
	return &view, nil
}

func (r *MetadataRepository) scanTheme(row Scannable) (*models.Theme, error) {
	var theme models.Theme
	var colorsJSON sql.NullString
	var createdDateVal, lastModifiedDateVal interface{}

	if err := row.Scan(
		&theme.ID, &theme.Name, &theme.IsActive,
		&colorsJSON, &theme.Density, &theme.LogoURL,
		&createdDateVal, &lastModifiedDateVal,
	); err != nil {
		return nil, err
	}

	if colorsJSON.Valid {
		r.unmarshalJSON(colorsJSON.String, &theme.Colors)
	}
	theme.CreatedDate = parseTime(createdDateVal)
	theme.LastModifiedDate = parseTime(lastModifiedDateVal)

	return &theme, nil
}

func (r *MetadataRepository) scanApprovalLayout(row Scannable) (*models.ApprovalPageLayout, error) {
	var id, objectAPIName, layoutName, configJSON string
	var typeVal, sourceVal sql.NullString
	var isDefault, isDeleted, isCustomized bool
	var layoutVersion, generationVersion int
	var createdDateVal, lastModifiedDateVal interface{}

	if err := row.Scan(&id, &objectAPIName, &layoutName, &typeVal, &isDefault, &isDeleted, &configJSON, &createdDateVal, &lastModifiedDateVal, &isCustomized, &layoutVersion, &sourceVal, &generationVersion); err != nil {
		return nil, err
	}

	var layout models.ApprovalPageLayout
	var config interface{}
	if err := json.Unmarshal([]byte(configJSON), &config); err != nil {
		return nil, err
	}
	layout.ID = id
	layout.ObjectAPIName = objectAPIName
	layout.LayoutName = layoutName
	layout.IsDefault = isDefault
	layout.IsDeleted = isDeleted
	layout.Config = config
	layout.IsCustomized = isCustomized
	layout.LayoutVersion = layoutVersion
	if sourceVal.Valid && sourceVal.String != "" {
		layout.Source = sourceVal.String
	} else {
		layout.Source = "auto_generated" // default for rows predating the migration
	}
	layout.GenerationVersion = generationVersion
	if typeVal.Valid {
		layout.Type = typeVal.String
	} else {
		layout.Type = "approval_response" // default for approval layouts
	}
	layout.CreatedDate = parseTime(createdDateVal)
	layout.LastModifiedDate = parseTime(lastModifiedDateVal)
	return &layout, nil
}
