import { ulid } from 'ulid';
import { query } from '../db/connection.js';

export interface Household {
  id: string;
  name: string;
  invite_code: string;
  created_at: string;
}

export interface HouseholdMember {
  user_id: string;
  email: string;
  display_name: string;
  avatar_url?: string;
  role: 'owner' | 'member';
  joined_at: string;
}

export interface HouseholdWithMembers extends Household {
  members: HouseholdMember[];
}

class HouseholdService {
  private generateInviteCode(): string {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    let result = '';
    for (let i = 0; i < 8; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return result;
  }

  private async generateUniqueInviteCode(): Promise<string> {
    let code: string;
    let attempts = 0;
    do {
      code = this.generateInviteCode();
      attempts++;
      if (attempts > 100) throw new Error('Could not generate unique invite code');
      const { rows } = await query('SELECT id FROM households WHERE invite_code = $1', [code]);
      if (rows.length === 0) return code;
    } while (true);
  }

  async createHousehold(userId: string, name: string): Promise<HouseholdWithMembers> {
    const { rows: existing } = await query('SELECT household_id FROM household_members WHERE user_id = $1', [userId]);
    if (existing.length > 0) throw new Error('USER_ALREADY_IN_HOUSEHOLD');

    const householdId = ulid();
    const inviteCode = await this.generateUniqueInviteCode();

    await query('INSERT INTO households (id, name, invite_code) VALUES ($1, $2, $3)', [householdId, name, inviteCode]);
    await query("INSERT INTO household_members (household_id, user_id, role) VALUES ($1, $2, 'owner')", [householdId, userId]);

    const household = await this.getMyHousehold(userId);
    if (!household) throw new Error('Failed to create household');
    return household;
  }

  async joinHousehold(userId: string, inviteCode: string): Promise<HouseholdWithMembers> {
    const { rows: existing } = await query('SELECT household_id FROM household_members WHERE user_id = $1', [userId]);
    if (existing.length > 0) throw new Error('USER_ALREADY_IN_HOUSEHOLD');

    const { rows: households } = await query('SELECT id FROM households WHERE invite_code = $1', [inviteCode]);
    if (households.length === 0) throw new Error('INVALID_INVITE_CODE');

    await query("INSERT INTO household_members (household_id, user_id, role) VALUES ($1, $2, 'member')", [households[0].id, userId]);

    const result = await this.getMyHousehold(userId);
    if (!result) throw new Error('Failed to join household');
    return result;
  }

  async getMyHousehold(userId: string): Promise<HouseholdWithMembers | null> {
    const { rows } = await query(`
      SELECT h.*, hm.role
      FROM households h
      JOIN household_members hm ON h.id = hm.household_id
      WHERE hm.user_id = $1
    `, [userId]);

    if (rows.length === 0) return null;
    const householdRow = rows[0];

    const { rows: members } = await query(`
      SELECT u.id as user_id, u.email, u.display_name, u.avatar_url, hm.role, hm.joined_at
      FROM household_members hm
      JOIN users u ON hm.user_id = u.id
      WHERE hm.household_id = $1
      ORDER BY hm.role DESC, hm.joined_at ASC
    `, [householdRow.id]);

    const { role, ...household } = householdRow;
    return { ...household, members };
  }

  async leaveHousehold(userId: string, householdId: string): Promise<void> {
    const { rows } = await query(
      'SELECT role FROM household_members WHERE user_id = $1 AND household_id = $2',
      [userId, householdId]
    );
    if (rows.length === 0) throw new Error('NOT_HOUSEHOLD_MEMBER');

    if (rows[0].role === 'owner') {
      const { rows: countRows } = await query('SELECT COUNT(*) as count FROM household_members WHERE household_id = $1', [householdId]);
      if (parseInt(countRows[0].count) > 1) throw new Error('OWNER_CANNOT_LEAVE_WITH_MEMBERS');
      await query('DELETE FROM households WHERE id = $1', [householdId]);
    } else {
      await query('DELETE FROM household_members WHERE user_id = $1 AND household_id = $2', [userId, householdId]);
    }
  }

  async regenerateInviteCode(userId: string, householdId: string): Promise<string> {
    const { rows } = await query(
      'SELECT role FROM household_members WHERE user_id = $1 AND household_id = $2',
      [userId, householdId]
    );
    if (rows.length === 0 || rows[0].role !== 'owner') throw new Error('ONLY_OWNER_CAN_REGENERATE_INVITE');

    const newCode = await this.generateUniqueInviteCode();
    await query('UPDATE households SET invite_code = $1 WHERE id = $2', [newCode, householdId]);
    return newCode;
  }

  async getHouseholdByInviteCode(inviteCode: string): Promise<Household | null> {
    const { rows } = await query('SELECT id, name, invite_code, created_at FROM households WHERE invite_code = $1', [inviteCode]);
    return rows[0] || null;
  }
}

export const householdService = new HouseholdService();
