import { chromium } from 'playwright';
import User from '../models/User.js';
import ClickTtAccount from '../models/ClickTtAccount.js';
import HttpError from '../exceptions/HttpError.js';

const CLICKTT_LOGIN_URL = 'https://httv.click-tt.de/cgi-bin/WebObjects/nuLigaTTDE.woa/wa/login?federation=HeTTV&region=DE';

class ClickTtAccountService {
  async getAccount(userId) {
    const account = await ClickTtAccount.findOne({ where: { userId } });
    if (!account) return null;

    return {
      id: account.id,
      userId: account.userId,
      username: account.username,
      savePassword: account.savePassword,
      lastLoginAttempt: account.lastLoginAttempt,
      lastLoginSuccess: account.lastLoginSuccess,
      createdAt: account.createdAt,
      updatedAt: account.updatedAt
    };
  }

  async checkAccountStatus(userId) {
    const account = await ClickTtAccount.findOne({ where: { userId } });
    return {
      exists: !!account,
      hasUsername: !!account?.username,
      hasPassword: !!(account?.savePassword && account?.encryptedPassword),
      hasValidSession: !!account?.playwrightStorageState,
      needsConfiguration: !account || !account.username,
      needsPassword: !!account && (!account.savePassword || !account.encryptedPassword)
    };
  }

  async upsertAccount(userId, username, password, savePassword, userPassword) {
    const user = await User.findByPk(userId);
    if (!user) {
      throw new HttpError({ code: 'ERROR_USER_NOT_FOUND' }, 404);
    }

    if (password) {
      const isValidPassword = await user.validatePassword(userPassword);
      if (!isValidPassword) {
        throw new HttpError('Ungültiges Passwort', 401);
      }
    }

    let account = await ClickTtAccount.findOne({ where: { userId } });
    const now = new Date();

    if (account) {
      account.username = username;
      account.savePassword = savePassword;
      account.lastLoginAttempt = password ? now : account.lastLoginAttempt;

      if (password && savePassword) {
        account.setPassword(password);
      } else if (!savePassword) {
        account.encryptedPassword = null;
      }
    } else {
      account = await ClickTtAccount.create({
        userId,
        username,
        savePassword,
        lastLoginAttempt: password ? now : null
      });
      if (password && savePassword) {
        account.setPassword(password);
      }
    }

    if (password) {
      const loginResult = await this._loginWithBrowserAutomation(username, password, account.playwrightStorageState ?? null);
      account.lastLoginSuccess = now;
      account.playwrightStorageState = loginResult.storageState;
    }

    await account.save();

    return this.getAccount(userId);
  }

  async deleteAccount(userId) {
    const deleted = await ClickTtAccount.destroy({ where: { userId } });
    return deleted > 0;
  }

  async verifyLogin(userId, providedPassword = null) {
    const account = await ClickTtAccount.findOne({ where: { userId } });
    if (!account) {
      throw new HttpError('Kein HTTV-/click-TT-Account verknüpft', 404);
    }

    const now = new Date();
    account.lastLoginAttempt = now;

    let password = providedPassword;
    if (!password && account.savePassword) {
      password = account.getPassword();
    }

    const loginResult = await this._loginWithBrowserAutomation(
      account.username,
      password,
      account.playwrightStorageState ?? null
    );

    account.lastLoginSuccess = now;
    account.playwrightStorageState = loginResult.storageState;
    await account.save();

    return { success: true };
  }

  async _loginWithBrowserAutomation(username, password, savedStorageState = null) {
    let browser;
    let context;
    let page;

    try {
      browser = await chromium.launch({
        headless: true,
        args: ['--no-sandbox', '--disable-dev-shm-usage']
      });
      context = savedStorageState
        ? await browser.newContext({ storageState: savedStorageState })
        : await browser.newContext();
      page = await context.newPage();

      await page.goto(CLICKTT_LOGIN_URL, { waitUntil: 'domcontentloaded', timeout: 45000 });

      const alreadyLoggedIn = await this._isLoggedIn(page);
      if (!alreadyLoggedIn) {
        if (!password) {
          throw new HttpError('Kein Passwort gespeichert. Bitte HTTV-/click-TT-Passwort hinterlegen.', 400);
        }

        const userField = page.locator('input[name="username"], input[name="email"], input[type="email"], input[autocomplete="username"]').first();
        const passwordField = page.locator('input[name="password"], input[type="password"]').first();

        await userField.fill(username, { timeout: 10000 });
        await passwordField.fill(password, { timeout: 10000 });

        const submitButton = page.locator('button[type="submit"], input[type="submit"]').first();
        await submitButton.click();
        await page.waitForLoadState('domcontentloaded', { timeout: 60000 });

        if (!(await this._isLoggedIn(page))) {
          const text = await page.locator('body').innerText().catch(() => '');
          throw new HttpError(`HTTV-/click-TT-Login fehlgeschlagen: ${String(text || '').replace(/\s+/g, ' ').trim().slice(0, 400)}`, 401);
        }
      }

      return {
        success: true,
        storageState: await context.storageState()
      };
    } finally {
      if (context) {
        try { await context.close(); } catch (_err) {}
      }
      if (browser) {
        try { await browser.close(); } catch (_err) {}
      }
    }
  }

  async _isLoggedIn(page) {
    const currentUrl = page.url();
    if (/ttde-id\.liga\.nu\/oauth2/.test(currentUrl)) {
      return false;
    }

    const logoutLink = page.getByRole('link', { name: /abmelden|logout/i }).first();
    if (await logoutLink.count()) {
      return true;
    }

    const applicationButton = page.locator('input[type="submit"][value*="Spielberechtigungen beantragen"], a:has-text("Spielberechtigungen beantragen")').first();
    if (await applicationButton.count()) {
      return true;
    }

    return /click-tt\.de/.test(currentUrl) && !/oauth2/.test(currentUrl);
  }
}

export default new ClickTtAccountService();
