import { describe, it, expect, beforeEach, vi } from 'vitest';
import type { User } from '@prisma/client';
import { prisma } from '@/lib/db';
import { resetDb, mkUser, mkOrder } from './helpers';

const me = vi.hoisted(() => ({ admin: null as User | null }));
vi.mock('@/lib/auth', () => ({ requireAdmin: async () => me.admin, currentUser: async () => me.admin }));
vi.mock('next/cache', () => ({ revalidatePath: () => {} }));
vi.mock('@/lib/notify', () => ({ sendEmail: async () => {}, notifyAgent: async () => {} }));
const A = await import('@/app/krtf1krtf/actions');

const fd = (o: Record<string, string>) => { const f = new FormData(); for (const [k, v] of Object.entries(o)) f.set(k, v); return f; };
beforeEach(async () => { await resetDb(); me.admin = await prisma.user.update({ where: { id: (await mkUser()).id }, data: { role: 'ADMIN' } }); });

describe('yönetici: kredi', () => {
  it('kredi ekler, 0 TL yönetici kaydı ve günlük yazar', async () => {
    const u = await mkUser(1);
    const r = await A.adjustCredits(undefined, fd({ id: u.id, delta: '3', note: 'telafi' }));
    expect(r?.ok).toBeTruthy();
    expect((await prisma.user.findUnique({ where: { id: u.id } }))!.credits).toBe(4);
    const p = await prisma.payment.findFirst({ where: { userId: u.id } });
    expect(p).toMatchObject({ plan: 'admin', credits: 3, amount: 0, status: 'succeeded' });
    expect(await prisma.adminLog.count({ where: { action: 'user.credits', targetId: u.id } })).toBe(1);
  });
  it('kullanıcının kredisinden fazlası düşülemez, hiçbir şey değişmez', async () => {
    const u = await mkUser(2);
    const r = await A.adjustCredits(undefined, fd({ id: u.id, delta: '-5', note: 'hatalı' }));
    expect(r?.error).toBeTruthy();
    expect((await prisma.user.findUnique({ where: { id: u.id } }))!.credits).toBe(2);
    expect(await prisma.payment.count()).toBe(0);
    expect(await prisma.adminLog.count()).toBe(0);
  });
  it('not olmadan kredi işlenmez', async () => {
    const u = await mkUser();
    expect((await A.adjustCredits(undefined, fd({ id: u.id, delta: '1', note: '' })))?.error).toBeTruthy();
  });
});

describe('yönetici: sipariş', () => {
  it('kuyruktaki siparişi iptal edip krediyi iade eder, işi iptal eder', async () => {
    const u = await mkUser(0); const o = await mkOrder(u.id, { status: 'QUEUED' });
    await prisma.job.create({ data: { orderId: o.id } });
    const r = await A.cancelOrder(undefined, fd({ id: o.id, refund: 'on' }));
    expect(r?.ok).toMatch(/iade/);
    expect((await prisma.order.findUnique({ where: { id: o.id } }))!.status).toBe('CANCELLED');
    expect((await prisma.user.findUnique({ where: { id: u.id } }))!.credits).toBe(1);
    expect((await prisma.job.findFirst({ where: { orderId: o.id } }))!.status).toBe('cancelled');
  });
  it('başarısız siparişte iptal ikinci kez kredi iade etmez (işçi zaten iade etti)', async () => {
    const u = await mkUser(0); const o = await mkOrder(u.id, { status: 'FAILED' });
    await A.cancelOrder(undefined, fd({ id: o.id, refund: 'on' }));
    expect((await prisma.user.findUnique({ where: { id: u.id } }))!.credits).toBe(0);
  });
  it('üretimdeki sipariş iptal edilemez', async () => {
    const u = await mkUser(); const o = await mkOrder(u.id, { status: 'RENDERING' });
    expect((await A.cancelOrder(undefined, fd({ id: o.id })))?.error).toBeTruthy();
    expect((await prisma.order.findUnique({ where: { id: o.id } }))!.status).toBe('RENDERING');
  });
  it('teslim edilmiş siparişi kredi düşmeden yeniden üretime alır', async () => {
    const u = await mkUser(0); const o = await mkOrder(u.id, { status: 'DELIVERED' });
    expect((await A.rerenderOrder(undefined, fd({ id: o.id })))?.ok).toBeTruthy();
    expect((await prisma.order.findUnique({ where: { id: o.id } }))!.status).toBe('QUEUED');
    expect(await prisma.job.count({ where: { orderId: o.id, status: 'queued' } })).toBe(1);
    expect((await prisma.user.findUnique({ where: { id: u.id } }))!.credits).toBe(0);
  });
  it('ödenmemiş sipariş yeniden üretilemez', async () => {
    const u = await mkUser(); const o = await mkOrder(u.id);
    expect((await A.rerenderOrder(undefined, fd({ id: o.id })))?.error).toBeTruthy();
    expect(await prisma.job.count()).toBe(0);
  });
});

describe('yönetici: hesap', () => {
  it('askıya alınan hesabın oturumları düşer; askı kaldırılabilir', async () => {
    const u = await mkUser();
    await A.setSuspended(undefined, fd({ id: u.id, on: '1', reason: 'sahte hesap' }));
    let x = await prisma.user.findUnique({ where: { id: u.id } });
    expect(x!.disabledAt).not.toBeNull(); expect(x!.sessionVersion).toBe(1);
    await A.setSuspended(undefined, fd({ id: u.id, on: '0' }));
    x = await prisma.user.findUnique({ where: { id: u.id } });
    expect(x!.disabledAt).toBeNull();
    expect(await prisma.adminLog.count({ where: { targetId: u.id } })).toBe(2);
  });
  it('yönetici kendi hesabını askıya alamaz, kendi rolünü değiştiremez', async () => {
    expect((await A.setSuspended(undefined, fd({ id: me.admin!.id, on: '1' })))?.error).toBeTruthy();
    expect((await A.setRole(undefined, fd({ id: me.admin!.id, role: 'USER' })))?.error).toBeTruthy();
    expect((await prisma.user.findUnique({ where: { id: me.admin!.id } }))!.role).toBe('ADMIN');
  });
  it('rol değişince kullanıcının oturumları yenilenir', async () => {
    const u = await mkUser();
    await A.setRole(undefined, fd({ id: u.id, role: 'ADMIN' }));
    const x = await prisma.user.findUnique({ where: { id: u.id } });
    expect(x!.role).toBe('ADMIN'); expect(x!.sessionVersion).toBe(1);
  });
});
