// content-writer.service.ts
import {BadRequestException, Injectable, Logger} from '@nestjs/common';
import {GenerateContentDto} from './dto/generate-content.dto';
import {ContentResponseDto} from './dto/content-response.dto';
import {StyleDetectorService} from './services/style-detector.service';
import {PromptBuilderService} from './services/prompt-builder.service';
import {ReviewerService} from './services/reviewer.service';
import {AIProviderFactory, ProviderName} from './providers/ai-provider.factory';
import {Platform} from "./enum/platform.enum";
import {ProviderRouterService} from "./services/provider-router.service";
import {Language} from "../../common/interfaces/language.prompt.interface";
import {WriterPromptParams} from "./interfaces/writer-prompt-params.interface";
import {AccountTier} from "./enum/account-tier.enum";
import {ConfigService} from "@nestjs/config";
import {LengthStrategyService} from "./services/length-strategy.service";
import {calculateTokenBudget} from "../../common/utils/token-calculator";

@Injectable()
export class ContentWriterService {
    private readonly logger = new Logger(ContentWriterService.name);

    constructor(
        private detector: StyleDetectorService,
        private promptBuilder: PromptBuilderService,
        private reviewer: ReviewerService,
        private factory: AIProviderFactory,
        private router: ProviderRouterService,
        private lengthStrategy: LengthStrategyService, // 👈 mới
        private configService: ConfigService,
    ) {
    }

    async getGrokAI() {
        return this.factory.get('grok');
    }

    async generate(
        dto: GenerateContentDto,
        isForceManualProvider: boolean = false,
        writerProvider: ProviderName = 'openai',
        reviewerProvider: ProviderName = 'deepseek',
    ): Promise<ContentResponseDto> {
        // 1. Detect style/tone nếu user không truyền (0 token)
        const style = dto.style ?? this.detector.detectStyle(dto.topic);
        const tone = dto.tone ?? this.detector.detectTone(dto.topic);
        const platform = dto.platform ? dto.platform : Platform.X;
        const language = (dto.language ?? 'en') as Language;

        // Default tier từ env nếu user không pass
        const tier = dto.accountTier ?? this.configService.get<AccountTier>(
            'X_ACCOUNT_TIER',
            AccountTier.PREMIUM,
        );

        // 📏 Decide length strategy
        const lengthDecision = this.lengthStrategy.decide({
            platform: dto.platform || Platform.X,
            tier,
            style,
            tone,
            requestedLength: dto.postLength,
        });
        this.logger.debug(`>>> style:${style} - tone:${tone} - pf:${platform} -lang:${language} - tier:${tier}`);
        this.logger.log(`Length: ${lengthDecision.reason}`);

        // 💰 Token budget
        const budget = calculateTokenBudget(lengthDecision.range, language);
        this.logger.log(`Budget: ${budget.minChars}-${budget.maxChars} chars, ${budget.maxTokens} tokens`);

        // 🧭 Smart routing
        const decision = this.router.route({
            language,
            contentType: 'post',
            style,
            tone,
        });
        this.logger.log(`ContentWriterService => Routing: ${decision.reason} - writer:${decision.writer} - reviewer:${decision.reviewer}`);

        const ctx: WriterPromptParams = {
            topic: dto.topic,
            platform,
            style,
            tone,
            language,
            extraInstructions: dto.extraInstructions,
            postLength: lengthDecision.postLength,       // 👈 pass xuống
            lengthRange: lengthDecision.range,
        };

        // 🌐 Optional: Grok enriches X context (chỉ dùng cho EN breaking)
        let enrichedTopic = dto.topic;
        let enrichmentTokens = 0;
        if (dto.useXEnrichment || decision.useXEnrichment) {
            this.logger.log(`==> Prepare X-AI enrich topic: ${enrichedTopic}`);
            try {
                const grok = this.factory.getGrok();
                const xContext = await grok.enrichXContext(dto.topic);
                enrichedTopic = `${dto.topic}\n\n[X Context]:\n${xContext}`;
                this.logger.log(`===> X enrichment: ${xContext}`);
            } catch (e) {
                this.logger.warn('===> X enrichment failed, proceeding without', e);
            }
        }

        // ✍️ Writer
        console.log('==> ContentWriterService_write: ');

        const provider = this.factory.get(isForceManualProvider ? writerProvider : decision.writer);
        const messages = this.promptBuilder.buildWriterMessages({
            ...ctx,
            topic: enrichedTopic
        });
        // console.debug('prompt message:==>', messages);
        const draft = await provider.complete(messages, {
            temperature: 0.75,
            maxTokens: budget.maxTokens,
        });
        this.logger.debug(`===> ${draft.model} đã viết xong!`);

        let final = draft.content;
        let totalTokens = draft.tokensUsed + enrichmentTokens;
        let reviewNotes: string | undefined;
        let modelUsed = draft.model;

        // 🔍 Reviewer
        if (dto.enableReview) {
            this.logger.debug(`===> chuẩn bị review`);
            try {
                const reviewed = await this.reviewer.review(
                    draft.content,
                    ctx,
                    isForceManualProvider ? reviewerProvider : decision.reviewer,
                    dto.topic,
                    Math.ceil(budget.maxTokens * 1.3),
                );
                final = reviewed.improved;
                reviewNotes = reviewed.notes;
                totalTokens += reviewed.tokensUsed;
                modelUsed = `${draft.model} + ${reviewed.model}`;
                this.logger.debug(`===> ${reviewed.model} đã review xong!`);
            } catch (err) {
                this.logger.error('Review failed, fallback to draft', err);
            }
        }

        // 🛡️ Hard cap check
        if (final.length > lengthDecision.hardLimit) {
            this.logger.warn(`==> Output exceeds hard limit (${final.length} > ${lengthDecision.hardLimit})`);
            // final = final.substring(0, lengthDecision.hardLimit);
        }

        // if ([ContentStyle.FINANCE, ContentStyle.CRYPTO].includes(ctx.style)) {
        //     final += `\n ⚠️ This content is for informational purposes only, not financial advice. DYOR. \n`
        // }
        return {
            topic: dto.topic,
            final,
            draft: dto.enableReview ? draft.content : undefined,
            reviewNotes,
            detectedStyle: style,
            detectedTone: tone,
            tokensUsed: totalTokens,
            model: modelUsed,
            prompt: JSON.stringify(messages),
        };
    }
}
