// Supra Theme - TypeScript Example
// This file demonstrates syntax highlighting for TypeScript

import { createClient, SupabaseClient } from "@supabase/supabase-js";

interface User {
  id: string;
  name: string;
  email: string;
  age?: number;
  createdAt: Date;
  updatedAt: Date;
}

interface DatabaseConfig {
  apiKey: string;
  url: string;
  timeout?: number;
}

type UserRole = "admin" | "user" | "moderator";

enum Status {
  ACTIVE = "active",
  INACTIVE = "inactive",
  PENDING = "pending",
}

class DatabaseService<T extends User> {
  private supabase: SupabaseClient;
  private isConnected: boolean = false;
  private readonly config: DatabaseConfig;

  constructor(config: DatabaseConfig) {
    this.config = config;
    this.supabase = createClient(config.url, config.apiKey);
  }

  async connect(): Promise<T[]> {
    try {
      const { data, error } = await this.supabase
        .from("users")
        .select("*")
        .limit(10);

      if (error) throw new Error(error.message);

      this.isConnected = true;
      console.log("Connected to database successfully");
      return data as T[];
    } catch (err) {
      console.error("Database connection failed:", err);
      throw err;
    }
  }

  async createUser(
    userData: Omit<T, "id" | "createdAt" | "updatedAt">
  ): Promise<T> {
    const { name, email, age } = userData;

    if (!name || !email) {
      throw new Error("Name and email are required");
    }

    const { data, error } = await this.supabase
      .from("users")
      .insert([
        {
          name,
          email,
          age: age || null,
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ])
      .select();

    if (error) throw new Error(error.message);
    return data[0] as T;
  }

  async findUsersByRole(role: UserRole): Promise<T[]> {
    const { data, error } = await this.supabase
      .from("users")
      .select("*")
      .eq("role", role);

    if (error) throw new Error(error.message);
    return data as T[];
  }

  // Generic method with constraints
  async updateUser<K extends keyof T>(
    id: string,
    updates: Partial<Pick<T, K>>
  ): Promise<T> {
    const { data, error } = await this.supabase
      .from("users")
      .update({ ...updates, updatedAt: new Date() })
      .eq("id", id)
      .select();

    if (error) throw new Error(error.message);
    return data[0] as T;
  }
}

// Utility types and function overloads
function processUserData(user: User): string;
function processUserData(users: User[]): string[];
function processUserData(input: User | User[]): string | string[] {
  if (Array.isArray(input)) {
    return input.map((user) => `${user.name} (${user.email})`);
  }
  return `${input.name} (${input.email})`;
}

// Async generator function
async function* fetchUsersInBatches(
  batchSize: number = 10
): AsyncGenerator<User[], void, unknown> {
  let offset = 0;
  let hasMore = true;

  while (hasMore) {
    const { data, error } = await this.supabase
      .from("users")
      .select("*")
      .range(offset, offset + batchSize - 1);

    if (error) throw new Error(error.message);

    if (data.length === 0) {
      hasMore = false;
    } else {
      yield data as User[];
      offset += batchSize;
    }
  }
}

// Decorator example
function LogMethod(
  target: any,
  propertyName: string,
  descriptor: PropertyDescriptor
) {
  const method = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`Calling ${propertyName} with args:`, args);
    return method.apply(this, args);
  };
}

class ApiController {
  @LogMethod
  async handleRequest(req: Request): Promise<Response> {
    // Implementation here
    return new Response("OK");
  }
}

export {
  DatabaseService,
  User,
  UserRole,
  Status,
  processUserData,
  fetchUsersInBatches,
};
