import { eq, and } from "drizzle-orm";
import { database } from "~/database/context";
import * as schema from "~/database/schema";

export type Season = typeof schema.seasons.$inferSelect;
export type NewSeason = Omit<typeof schema.seasons.$inferInsert, 'inviteCode'> & {
  inviteCode?: string;
};
export type SeasonStatus = "pre_draft" | "draft" | "active" | "completed";

export interface SeasonWithSportsSeasons extends Season {
  seasonSports: Array<{
    id: string;
    sportsSeason: {
      id: string;
      name: string;
      year: number;
      status: string;
      scoringType: string;
      scoringPattern: string | null;
      isDraftable: boolean;
      sport: {
        id: string;
        name: string;
        type: string;
        slug: string;
      };
    };
  }>;
}

export async function createSeason(data: NewSeason): Promise<Season> {
  const db = database();
  
  // Generate invite code if not provided
  const seasonData = {
    ...data,
    inviteCode: data.inviteCode || generateInviteCode(),
  };
  
  const [season] = await db
    .insert(schema.seasons)
    .values(seasonData)
    .returning();
  return season;
}

export async function findSeasonById(id: string): Promise<Season | undefined> {
  const db = database();
  return await db.query.seasons.findFirst({
    where: eq(schema.seasons.id, id),
  });
}

export async function findSeasonsByLeagueId(leagueId: string): Promise<Season[]> {
  const db = database();
  return await db.query.seasons.findMany({
    where: eq(schema.seasons.leagueId, leagueId),
    orderBy: (seasons, { desc }) => [desc(seasons.year)],
  });
}

export async function findCurrentSeason(
  leagueId: string
): Promise<Season | undefined> {
  const db = database();
  return await db.query.seasons.findFirst({
    where: eq(schema.seasons.leagueId, leagueId),
    orderBy: (seasons, { desc }) => [desc(seasons.year)],
  });
}

export async function findCurrentSeasonWithSports(
  leagueId: string
): Promise<SeasonWithSportsSeasons | undefined> {
  const db = database();
  return await db.query.seasons.findFirst({
    where: eq(schema.seasons.leagueId, leagueId),
    orderBy: (seasons, { desc }) => [desc(seasons.year)],
    with: {
      seasonSports: {
        with: {
          sportsSeason: {
            with: {
              sport: true,
            },
          },
        },
      },
    },
  }) as SeasonWithSportsSeasons | undefined;
}

export async function findSeasonByLeagueAndYear(
  leagueId: string,
  year: number
): Promise<Season | undefined> {
  const db = database();
  return await db.query.seasons.findFirst({
    where: and(
      eq(schema.seasons.leagueId, leagueId),
      eq(schema.seasons.year, year)
    ),
  });
}

export async function updateSeason(
  id: string,
  data: Partial<NewSeason>
): Promise<Season> {
  const db = database();
  const [season] = await db
    .update(schema.seasons)
    .set({ ...data, updatedAt: new Date() })
    .where(eq(schema.seasons.id, id))
    .returning();
  return season;
}

export async function updateSeasonStatus(
  id: string,
  status: SeasonStatus
): Promise<Season> {
  return await updateSeason(id, { status });
}

export async function deleteSeason(id: string): Promise<void> {
  const db = database();
  await db.delete(schema.seasons).where(eq(schema.seasons.id, id));
}

export async function findSeasonWithSportsSeasons(
  id: string
): Promise<SeasonWithSportsSeasons | undefined> {
  const db = database();
  return await db.query.seasons.findFirst({
    where: eq(schema.seasons.id, id),
    with: {
      seasonSports: {
        with: {
          sportsSeason: {
            with: {
              sport: true,
            },
          },
        },
      },
    },
  }) as SeasonWithSportsSeasons | undefined;
}

/**
 * Generate a short, URL-safe invite code
 * Uses base62 encoding (alphanumeric) for readability
 */
export function generateInviteCode(): string {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  const length = 10;
  let result = '';
  const randomValues = new Uint8Array(length);
  crypto.getRandomValues(randomValues);
  
  for (let i = 0; i < length; i++) {
    result += chars[randomValues[i] % chars.length];
  }
  
  return result;
}

/**
 * Find a season by its invite code
 */
export async function findSeasonByInviteCode(
  inviteCode: string
): Promise<Season | undefined> {
  const db = database();
  return await db.query.seasons.findFirst({
    where: eq(schema.seasons.inviteCode, inviteCode),
  });
}

/**
 * Regenerate invite code for a season
 */
export async function regenerateInviteCode(seasonId: string): Promise<Season> {
  const newInviteCode = generateInviteCode();
  return await updateSeason(seasonId, { inviteCode: newInviteCode });
}
