package applogic

import (
	"context"
	"fmt"
	"strings"
	"time"

	"aijianzhan/platform/internal/authx"
	"aijianzhan/platform/internal/invitestore"
	"aijianzhan/platform/internal/svc"
	"aijianzhan/platform/internal/types"
	"aijianzhan/platform/internal/userstore"
)

func (l *AuthLogic) issueUser(u *userstore.User) (*types.TokenResp, error) {
	resp, err := l.issue(u.TenantID, u.UserID, u.Role, u.Username, u.DisplayName, u.OrgUnitID)
	if err != nil {
		return nil, err
	}
	resp.Phone = u.Phone
	resp.UsernameLoginDisabled = u.UsernameLoginDisabled
	resp.Status = u.Status
	if resp.Status == "" {
		if u.HasTenant() || u.IsPlatformAdmin() {
			resp.Status = userstore.StatusActive
		} else {
			resp.Status = userstore.StatusPending
		}
	}
	fillUserSyncOnToken(l.svcCtx, resp, u)
	if u.IsPlatformAdmin() {
		resp.Message = "平台超级管理员工作台：管理全部公司；打开某公司可查看其内部功能"
		return resp, nil
	}
	if !u.HasTenant() {
		resp.Message = "账号待加入租户：请使用邀请码加入公司，或创建自己的公司"
	}
	return resp, nil
}

func (l *AuthLogic) AcceptInvite(req *types.InviteAcceptReq) (*types.TokenResp, error) {
	if l.svcCtx.Users == nil || l.svcCtx.Invites == nil {
		return nil, fmt.Errorf("invite store unavailable")
	}
	code := strings.TrimSpace(req.Code)
	if code == "" {
		return nil, fmt.Errorf("invite code required")
	}
	userID := authx.UserID(l.ctx)
	cur, err := l.svcCtx.Users.GetByID(l.ctx, userID)
	if err != nil {
		return nil, err
	}
	if cur.HasTenant() {
		return nil, fmt.Errorf("already joined a tenant")
	}
	inv, err := l.svcCtx.Invites.GetByCode(l.ctx, code)
	if err != nil {
		return nil, fmt.Errorf("invalid invite code")
	}
	if err := invitestore.ValidateUsable(inv); err != nil {
		return nil, err
	}
	if inv.OrgUnitID > 0 && l.svcCtx.OrgUnits != nil {
		if _, err := l.svcCtx.OrgUnits.Get(l.ctx, inv.TenantID, inv.OrgUnitID); err != nil {
			return nil, fmt.Errorf("invite org unit invalid")
		}
	}
	if err := l.svcCtx.Invites.Consume(l.ctx, inv.InviteID); err != nil {
		return nil, err
	}
	u, err := l.svcCtx.Users.JoinTenant(l.ctx, userID, inv.TenantID, inv.Role, inv.OrgUnitID)
	if err != nil {
		return nil, err
	}
	if l.svcCtx.Roles != nil {
		_ = l.svcCtx.Roles.EnsureDefaults(l.ctx, u.TenantID)
	}
	resp, err := l.issueUser(u)
	if err != nil {
		return nil, err
	}
	resp.Message = "已加入租户"
	return resp, nil
}

func (l *AuthLogic) CreateTenant(req *types.TenantCreateReq) (*types.TokenResp, error) {
	if l.svcCtx.Users == nil {
		return nil, fmt.Errorf("user store unavailable")
	}
	userID := authx.UserID(l.ctx)
	u, err := l.svcCtx.Users.CreateTenantAsOwner(l.ctx, userID, req.Name)
	if err != nil {
		return nil, err
	}
	if l.svcCtx.Roles != nil {
		_ = l.svcCtx.Roles.EnsureDefaults(l.ctx, u.TenantID)
	}
	if l.svcCtx.TenantPerm != nil {
		_ = l.svcCtx.TenantPerm.EnsureDefault(l.ctx, u.TenantID)
	}
	resp, err := l.issueUser(u)
	if err != nil {
		return nil, err
	}
	resp.Message = "已创建公司并成为管理员"
	return resp, nil
}

type InviteAdminLogic struct {
	AuthLogic
}

func NewInviteAdminLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InviteAdminLogic {
	return &InviteAdminLogic{AuthLogic: AuthLogic{ctx: ctx, svcCtx: svcCtx}}
}

func (l *InviteAdminLogic) List() ([]invitestore.Invite, error) {
	if l.svcCtx.Invites == nil {
		return nil, fmt.Errorf("invite store unavailable")
	}
	return l.svcCtx.Invites.List(l.ctx, authx.TenantID(l.ctx))
}

func (l *InviteAdminLogic) Create(req *types.InviteCreateReq) (*invitestore.Invite, error) {
	if l.svcCtx.Invites == nil {
		return nil, fmt.Errorf("invite store unavailable")
	}
	tid := authx.TenantID(l.ctx)
	if req.OrgUnitID > 0 {
		if l.svcCtx.OrgUnits == nil {
			return nil, fmt.Errorf("org unit store unavailable")
		}
		if _, err := l.svcCtx.OrgUnits.Get(l.ctx, tid, req.OrgUnitID); err != nil {
			return nil, fmt.Errorf("invalid org_unit_id")
		}
	}
	in := invitestore.CreateInput{
		Role:      req.Role,
		OrgUnitID: req.OrgUnitID,
		MaxUses:   req.MaxUses,
	}
	if req.ExpiresInHours > 0 {
		in.ExpiresIn = time.Duration(req.ExpiresInHours) * time.Hour
	}
	return l.svcCtx.Invites.Create(l.ctx, tid, authx.UserID(l.ctx), in)
}

func (l *InviteAdminLogic) Revoke(inviteID int64) error {
	if l.svcCtx.Invites == nil {
		return fmt.Errorf("invite store unavailable")
	}
	return l.svcCtx.Invites.Revoke(l.ctx, authx.TenantID(l.ctx), inviteID)
}
