// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_27

import (
	"fmt"
	"strings"
	"time"

	"gitea.dev/models/db"
	"gitea.dev/models/migrations/base"

	"xorm.io/xorm/schemas"
)

// legacyDateTimeColumns are the persisted real datetime columns that old Gitea
// versions created as MSSQL DATETIME. Every other time value is stored as a
// unix timestamp integer, so these are the only columns affected.
var legacyDateTimeColumns = []struct {
	bean   any
	column string
}{
	{new(externalLoginUserWithExpiresAt), "expires_at"},
	{new(lfsLockWithCreated), "created"},
}

type externalLoginUserWithExpiresAt struct {
	ExpiresAt time.Time
}

func (externalLoginUserWithExpiresAt) TableName() string {
	return "external_login_user"
}

type lfsLockWithCreated struct {
	Created time.Time `xorm:"created"`
}

func (lfsLockWithCreated) TableName() string {
	return "lfs_lock"
}

// FixLegacyMSSQLDateTimeColumns converts legacy locale-dependent DATETIME columns
// to DATETIME2. Databases created by old Gitea versions stored these columns as
// DATETIME, which fails to parse ISO datetime strings ('YYYY-MM-DD HH:MM:SS')
// when the MSSQL session language is not English, breaking external account
// linking and LFS lock creation. New installs already use DATETIME2, so only
// legacy MSSQL columns need converting.
func FixLegacyMSSQLDateTimeColumns(x db.EngineMigration) error {
	if x.Dialect().URI().DBType != schemas.MSSQL {
		return nil
	}

	for _, c := range legacyDateTimeColumns {
		table, err := x.TableInfo(c.bean)
		if err != nil {
			return err
		}

		var dataType string
		has, err := x.SQL("SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND COLUMN_NAME = ?", table.Name, c.column).Get(&dataType)
		if err != nil {
			return err
		}
		if !has || !strings.EqualFold(dataType, "datetime") {
			continue
		}

		column := table.GetColumn(c.column)
		if column == nil {
			return fmt.Errorf("column %s does not exist in table %s", c.column, table.Name)
		}
		if err := base.ModifyColumn(x, table.Name, column); err != nil {
			return fmt.Errorf("modify %s.%s: %w", table.Name, c.column, err)
		}
	}

	return nil
}
