package sqlite

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

	"switchboard-core/models"
	"switchboard-core/store"
)

type TeamStore struct{}

func NewTeamStore() *TeamStore { return &TeamStore{} }

func (s *TeamStore) Create(ctx context.Context, t *models.Team) error {
	settingsJSON := ToJSON(t.Settings)
	t.ID = store.NewID()
	now := time.Now().UTC()
	t.CreatedAt = now
	t.UpdatedAt = now
	_, err := DB.ExecContext(ctx, `
		INSERT INTO teams (id, name, description, created_by, is_active, settings, created_at, updated_at)
		VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
		t.ID, t.Name, t.Description, t.CreatedBy, t.IsActive, settingsJSON,
		now.Format(timeFmt), now.Format(timeFmt),
	)
	return err
}

func (s *TeamStore) GetByID(ctx context.Context, id string) (*models.Team, error) {
	var t models.Team
	var settingsJSON []byte
	err := DB.QueryRowContext(ctx, `
		SELECT id, name, description, created_by, is_active, settings, created_at, updated_at,
			(SELECT COUNT(*) FROM team_members WHERE team_id = teams.id) as member_count
		FROM teams WHERE id = ?`, id).Scan(
		&t.ID, &t.Name, &t.Description, &t.CreatedBy, &t.IsActive,
		&settingsJSON, st(&t.CreatedAt), st(&t.UpdatedAt), &t.MemberCount,
	)
	if err != nil {
		return nil, err
	}
	json.Unmarshal(settingsJSON, &t.Settings)
	return &t, nil
}

func (s *TeamStore) Update(ctx context.Context, id string, fields map[string]interface{}) error {
	b := NewUpdate("teams")
	for k, v := range fields {
		if k == "settings" {
			b.SetJSON(k, v)
		} else {
			b.Set(k, v)
		}
	}
	if !b.HasSets() {
		return nil
	}
	b.Where("id", id)
	_, err := b.Exec(DB)
	return err
}

func (s *TeamStore) Delete(ctx context.Context, id string) error {
	_, err := DB.ExecContext(ctx, "DELETE FROM teams WHERE id = ?", id)
	return err
}

func (s *TeamStore) List(ctx context.Context) ([]models.Team, error) {
	rows, err := DB.QueryContext(ctx, `
		SELECT id, name, description, created_by, is_active, settings, created_at, updated_at,
			(SELECT COUNT(*) FROM team_members WHERE team_id = teams.id) as member_count
		FROM teams ORDER BY name`)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var result []models.Team
	for rows.Next() {
		var t models.Team
		var settingsJSON []byte
		err := rows.Scan(&t.ID, &t.Name, &t.Description, &t.CreatedBy, &t.IsActive,
			&settingsJSON, st(&t.CreatedAt), st(&t.UpdatedAt), &t.MemberCount)
		if err != nil {
			return nil, err
		}
		json.Unmarshal(settingsJSON, &t.Settings)
		result = append(result, t)
	}
	return result, rows.Err()
}

func (s *TeamStore) ListForUser(ctx context.Context, userID string) ([]models.Team, error) {
	rows, err := DB.QueryContext(ctx, `
		SELECT t.id, t.name, t.description, t.created_by, t.is_active,
		       COALESCE(t.settings, '{}'), t.created_at, t.updated_at,
		       tm.role AS my_role,
		       (SELECT COUNT(*) FROM team_members WHERE team_id = t.id) AS member_count
		FROM teams t
		JOIN team_members tm ON tm.team_id = t.id AND tm.user_id = ?
		WHERE t.is_active = 1
		ORDER BY t.name ASC`, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var result []models.Team
	for rows.Next() {
		var t models.Team
		var settingsJSON []byte
		err := rows.Scan(&t.ID, &t.Name, &t.Description, &t.CreatedBy, &t.IsActive,
			&settingsJSON, st(&t.CreatedAt), st(&t.UpdatedAt), &t.MyRole, &t.MemberCount)
		if err != nil {
			return nil, err
		}
		json.Unmarshal(settingsJSON, &t.Settings)
		result = append(result, t)
	}
	return result, rows.Err()
}

// ── Members ─────────────────────────────────

func (s *TeamStore) AddMember(ctx context.Context, teamID, userID, role string) error {
	_, err := DB.ExecContext(ctx, `
		INSERT INTO team_members (id, team_id, user_id, role) VALUES (?, ?, ?, ?)
		ON CONFLICT (team_id, user_id) DO UPDATE SET role = excluded.role`,
		store.NewID(), teamID, userID, role)
	return err
}

func (s *TeamStore) RemoveMember(ctx context.Context, teamID, userID string) error {
	_, err := DB.ExecContext(ctx, "DELETE FROM team_members WHERE team_id = ? AND user_id = ?",
		teamID, userID)
	return err
}

func (s *TeamStore) UpdateMemberRole(ctx context.Context, teamID, userID, role string) error {
	_, err := DB.ExecContext(ctx,
		"UPDATE team_members SET role = ? WHERE team_id = ? AND user_id = ?",
		role, teamID, userID)
	return err
}

func (s *TeamStore) ListMembers(ctx context.Context, teamID string) ([]models.TeamMember, error) {
	rows, err := DB.QueryContext(ctx, `
		SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.joined_at,
			u.email, COALESCE(u.display_name, ''), u.username
		FROM team_members tm
		JOIN users u ON u.id = tm.user_id
		WHERE tm.team_id = ?
		ORDER BY tm.role DESC, u.username`, teamID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var result []models.TeamMember
	for rows.Next() {
		var m models.TeamMember
		err := rows.Scan(&m.ID, &m.TeamID, &m.UserID, &m.Role, &m.JoinedAt,
			&m.Email, &m.DisplayName, &m.Username)
		if err != nil {
			return nil, err
		}
		result = append(result, m)
	}
	return result, rows.Err()
}

func (s *TeamStore) GetMember(ctx context.Context, teamID, userID string) (*models.TeamMember, error) {
	var m models.TeamMember
	err := DB.QueryRowContext(ctx, `
		SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.joined_at,
			u.email, COALESCE(u.display_name, ''), u.username
		FROM team_members tm
		JOIN users u ON u.id = tm.user_id
		WHERE tm.team_id = ? AND tm.user_id = ?`, teamID, userID).Scan(
		&m.ID, &m.TeamID, &m.UserID, &m.Role, &m.JoinedAt,
		&m.Email, &m.DisplayName, &m.Username)
	if err != nil {
		return nil, err
	}
	return &m, nil
}

// GetUserTeamIDs returns all team IDs a user belongs to.
func (s *TeamStore) GetUserTeamIDs(ctx context.Context, userID string) ([]string, error) {
	rows, err := DB.QueryContext(ctx,
		"SELECT team_id FROM team_members WHERE user_id = ?", userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var ids []string
	for rows.Next() {
		var id string
		if err := rows.Scan(&id); err != nil {
			return nil, err
		}
		ids = append(ids, id)
	}
	return ids, rows.Err()
}

func (s *TeamStore) IsTeamAdmin(ctx context.Context, teamID, userID string) (bool, error) {
	var role string
	err := DB.QueryRowContext(ctx,
		"SELECT role FROM team_members WHERE team_id = ? AND user_id = ?",
		teamID, userID).Scan(&role)
	if err == sql.ErrNoRows {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	return role == models.TeamRoleAdmin, nil
}

func (s *TeamStore) IsMember(ctx context.Context, teamID, userID string) (bool, error) {
	var exists bool
	err := DB.QueryRowContext(ctx,
		"SELECT EXISTS(SELECT 1 FROM team_members WHERE team_id = ? AND user_id = ?)",
		teamID, userID).Scan(&exists)
	return exists, err
}


// ── CS1 additions (v0.29.0) ─────────────────────────────────────────────

func (s *TeamStore) Exists(ctx context.Context, teamID string) (bool, error) {
	var count int
	err := DB.QueryRowContext(ctx,
		`SELECT COUNT(*) FROM teams WHERE id = ?`, teamID).Scan(&count)
	return count > 0, err
}

func (s *TeamStore) UpdateMemberRoleByID(ctx context.Context, memberID, teamID, role string) (int64, error) {
	res, err := DB.ExecContext(ctx,
		`UPDATE team_members SET role = ? WHERE id = ? AND team_id = ?`,
		role, memberID, teamID)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (s *TeamStore) DeleteMemberByID(ctx context.Context, memberID, teamID string) (int64, error) {
	res, err := DB.ExecContext(ctx,
		`DELETE FROM team_members WHERE id = ? AND team_id = ?`,
		memberID, teamID)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (s *TeamStore) ListTeamAuditActions(ctx context.Context, teamID string) ([]string, error) {
	rows, err := DB.QueryContext(ctx, `
		SELECT DISTINCT al.action
		FROM audit_log al
		WHERE al.actor_id IN (SELECT user_id FROM team_members WHERE team_id = ?)
		ORDER BY al.action
	`, teamID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var actions []string
	for rows.Next() {
		var a string
		if err := rows.Scan(&a); err != nil {
			return nil, err
		}
		actions = append(actions, a)
	}
	if actions == nil {
		actions = []string{}
	}
	return actions, rows.Err()
}

// ── CS5b additions (v0.29.0) ────────────────────────────────────────────

func (s *TeamStore) GetFirstTeamIDForUser(ctx context.Context, userID string) (string, error) {
	var teamID string
	err := DB.QueryRowContext(ctx,
		`SELECT team_id FROM team_members WHERE user_id = ? LIMIT 1`, userID).Scan(&teamID)
	if err != nil {
		return "", nil
	}
	return teamID, nil
}

// ── CS6 additions (v0.29.0) ────────────────────────────────────────────

func (s *TeamStore) AddMemberReturningID(ctx context.Context, teamID, userID, role string) (string, error) {
	id := store.NewID()
	_, err := DB.ExecContext(ctx, `
		INSERT INTO team_members (id, team_id, user_id, role)
		VALUES (?, ?, ?, ?)`, id, teamID, userID, role)
	return id, err
}

func (s *TeamStore) MergeSettings(ctx context.Context, teamID, settingsJSON string) error {
	_, err := DB.ExecContext(ctx,
		`UPDATE teams SET settings = json_patch(COALESCE(settings, '{}'), ?) WHERE id = ?`,
		settingsJSON, teamID)
	return err
}
