package domain

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

// SocialAccount models a persisted OAuth binding.
type SocialAccount struct {
	ID        int64               `gorm:"primaryKey;autoIncrement" json:"id"`
	UserID    int64               `gorm:"index;not null" json:"user_id"`
	Provider  string              `gorm:"type:varchar(50);not null" json:"provider"`
	OpenID    string              `gorm:"type:varchar(100);not null" json:"open_id"`
	UnionID   string              `gorm:"type:varchar(100)" json:"union_id,omitempty"`
	Nickname  string              `gorm:"type:varchar(100)" json:"nickname"`
	Avatar    string              `gorm:"type:varchar(500)" json:"avatar"`
	Gender    string              `gorm:"type:varchar(10)" json:"gender,omitempty"`
	Email     string              `gorm:"type:varchar(100)" json:"email,omitempty"`
	Phone     string              `gorm:"type:varchar(20)" json:"phone,omitempty"`
	Extra     ExtraData           `gorm:"type:text" json:"extra,omitempty"`
	Status    SocialAccountStatus `gorm:"default:1" json:"status"`
	CreatedAt *time.Time      `json:"created_at"`
	UpdatedAt *time.Time      `json:"updated_at"`
}

func (SocialAccount) TableName() string {
	return "user_social_accounts"
}

type SocialAccountStatus int

const (
	SocialAccountStatusActive   SocialAccountStatus = 1
	SocialAccountStatusInactive SocialAccountStatus = 0
	SocialAccountStatusDisabled SocialAccountStatus = 2
)

type ExtraData map[string]interface{}

func (e ExtraData) Value() (driver.Value, error) {
	if e == nil {
		return nil, nil
	}
	return json.Marshal(e)
}

func (e *ExtraData) Scan(value interface{}) error {
	if value == nil {
		*e = nil
		return nil
	}
	bytes, ok := value.([]byte)
	if !ok {
		return nil
	}
	return json.Unmarshal(bytes, e)
}

type SocialAccountInfo struct {
	ID        int64               `json:"id"`
	Provider  string              `json:"provider"`
	Nickname  string              `json:"nickname"`
	Avatar    string              `json:"avatar"`
	Status    SocialAccountStatus `json:"status"`
	CreatedAt *time.Time         `json:"created_at"`
}

func (s *SocialAccount) ToInfo() *SocialAccountInfo {
	createdAt := s.CreatedAt
	return &SocialAccountInfo{
		ID:        s.ID,
		Provider:  s.Provider,
		Nickname:  s.Nickname,
		Avatar:    s.Avatar,
		Status:    s.Status,
		CreatedAt: createdAt,
	}
}
