# app.py
from flask import Flask, render_template, request, redirect, url_for, session, flash, send_file
from openai import OpenAI
import datetime
import json
from config import Config
import tempfile
import os
from fpdf import FPDF

app = Flask(__name__)
app.config.from_object(Config)

client = OpenAI(api_key=app.config['OPENAI_API_KEY'])

# プロンプト作成関数
def create_prompt(system_prompt, user_prompt):
    prompt = f"""
    {system_prompt}

    {user_prompt}
    """
    return prompt

# PDF作成クラス（大幅に修正）
class PDF(FPDF):
    def header(self):
        if self.page_no() != 1: # ヘッダーはタイトルページには不要
            self.add_font("IPAGothic", "", "ipag.ttf", uni=True)
            self.set_font('IPAGothic', '', 12)
            self.cell(0, 10, session['selected_title'], 0, 1, 'C')

    def footer(self):
        if self.page_no() != 1: # フッターもタイトルページと最終ページには不要
          self.set_y(-15)
          self.add_font("IPAGothic", "", "ipag.ttf", uni=True)
          self.set_font('IPAGothic', '', 8)
          self.cell(0, 10, 'Page ' + str(self.page_no()), 0, 0, 'C')


    def chapter_title(self, title):
        self.add_font("IPAGothic", "", "ipag.ttf", uni=True)
        self.set_font('IPAGothic', '', 16)
        self.cell(0, 10, title, 0, 1, 'L')
        self.ln(5)

    def chapter_body(self, body):
        self.add_font("IPAGothic", "", "ipag.ttf", uni=True)
        self.set_font('IPAGothic', '', 12)
        self.multi_cell(0, 10, body)
        self.ln()

    def add_cover_page(self):
        self.add_page()
        self.add_font("IPAGothic", "", "ipag.ttf", uni=True)
        # タイトル
        self.set_font('IPAGothic', '', 24)
        self.cell(0, 20, session['selected_title'], 0, 1, 'C')

        # 画像
        if 'image_file_path' in session:
            self.image(session['image_file_path'], x=10, y=50, w=190)

        # 著者情報 (下部に配置)
        self.set_font('IPAGothic', '', 12)
        self.set_y(-50) # y座標を下の方へ
        self.cell(0, 10, f"著者: {session['nickname']}", 0, 1, 'C')
        #self.cell(0, 10, f"メールアドレス: {session['email']}", 0, 1, 'C')  # メールアドレスは削除
        self.set_y(-30)
        self.set_font('IPAGothic', '', 10)
        self.multi_cell(0, 10, "この小説と画像は小説執筆AI 無限ライターが作成しました", 0, 'C') # 文言追加


    def add_last_page(self):
        self.add_page()
        self.add_font("IPAGothic", "", "ipag.ttf", uni=True)
        self.set_font('IPAGothic', '', 10)
        self.set_y(140)  # 中央付近
        #self.multi_cell(0, 10, "この小説と画像は小説執筆AI 無限ライターが作成しました", 0, 'C') # 削除

# エラーハンドリング
@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        session['nickname'] = request.form['nickname']
        session['email'] = request.form['email']

        return redirect(url_for('input_genre'))
    return render_template('index.html')

@app.route('/input_genre', methods=['GET', 'POST'])
def input_genre():
    if request.method == 'POST':
        session['genre'] = request.form['genre']

        return redirect(url_for('generate_title'))

    return render_template('input_genre.html')

@app.route('/thinking_title')
def thinking_title():
    description = "魅力的な小説のタイトルを考えています..."
    return render_template('thinking.html', next_url=url_for('generate_title'), description=description)

@app.route('/generate_title')
def generate_title():
    system_prompt = """
    あなたはプロの小説家です。
    次のジャンルに沿って、魅力的な小説のタイトル案を5つ、30文字以上60文字以内でJSON形式で出力してください。
    あまり堅苦しくない表現で。
    出力フォーマット：
    {
        "titles": [
            {"title": "タイトル1"},
            {"title": "タイトル2"},
            {"title": "タイトル3"}
           ]
    }
    """

    user_prompt = f"""
    小説のジャンル: {session['genre']}
    """

    prompt = create_prompt(system_prompt, user_prompt)

    response = client.chat.completions.create(
        model=app.config['MODEL_NAME'],
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_prompt}
        ],
        response_format={ "type": "json_object" },
        temperature=app.config['TEMPERATURE'],
        max_tokens=app.config['MAX_TOKENS']
    )

    titles = json.loads(response.choices[0].message.content)
    session['titles'] = titles['titles']
    return render_template('title.html', titles=titles['titles'])



@app.route('/select_title', methods=['POST'])
def select_title():
    selected_title_index = int(request.form['title'])
    session['selected_title'] = session['titles'][selected_title_index]['title']
    return redirect(url_for('thinking_characters'))

@app.route('/thinking_characters')
def thinking_characters():
    description = "小説に登場するキャラクターを考えています..."
    return render_template('thinking.html', next_url=url_for('generate_characters'), description=description)

@app.route('/generate_characters')
def generate_characters():
    system_prompt = """
    あなたはプロの小説家です。
     次の小説のタイトルとジャンルに基づいて、魅力的な登場人物候補を5人、JSON形式で出力してください。
    各登場人物は、名前、年齢、性別、性格、簡単な背景を含めてください。
    出力フォーマット：
    {
        "characters":[
            {
                "name": "名前",
                "age": "年齢",
                "personality": "性格",
                "background": "背景"
            },
           ...
        ]
    }
    """
    user_prompt = f"""
    小説のタイトル： {session['selected_title']}
    小説のジャンル： {session['genre']}
    """

    prompt = create_prompt(system_prompt, user_prompt)

    response = client.chat.completions.create(
        model=app.config['MODEL_NAME'],
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_prompt}
        ],
        response_format={ "type": "json_object" },
        temperature=app.config['TEMPERATURE'],
        max_tokens=app.config['MAX_TOKENS']
    )

    characters = json.loads(response.choices[0].message.content)
    session['characters'] = characters['characters']
    return render_template('characters.html', characters=characters['characters'])

@app.route('/select_characters', methods=['POST'])
def select_characters():
    selected_characters_indices = [int(i) for i in request.form.getlist('characters')]
    if len(selected_characters_indices) != 3:
        flash('登場人物は3人選択してください。')  # エラーメッセージを表示
        return redirect(url_for('generate_characters'))  # 前のページに戻る

    session['selected_characters'] = [session['characters'][i] for i in selected_characters_indices]
    return redirect(url_for('thinking_plot'))

@app.route('/thinking_plot')
def thinking_plot():
    description = "小説のあらすじを考えています..."
    return render_template('thinking.html', next_url=url_for('generate_plot'), description=description)

@app.route('/generate_plot')
def generate_plot():
    system_prompt = """
    あなたはプロの小説家です。
    以下の情報をもとに、200字程度のあらすじを3パターン作成し、JSON形式で出力してください。
    出力フォーマット:
    {
        "plots": [
            {"plot": "あらすじ1"},
            {"plot": "あらすじ2"},
            {"plot": "あらすじ3"}
        ]
    }
    """

    user_prompt = f"""
    小説のタイトル：{session['selected_title']}
    ジャンル：{session['genre']}
    登場人物：
    {session['selected_characters']}
    """

    prompt = create_prompt(system_prompt, user_prompt)

    response = client.chat.completions.create(
        model=app.config['MODEL_NAME'],
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_prompt}
        ],
        response_format={ "type": "json_object" },
        temperature=app.config['TEMPERATURE'],
        max_tokens=app.config['MAX_TOKENS']
    )

    plots = json.loads(response.choices[0].message.content)
    session['plots'] = plots['plots']
    return render_template('plot.html', plots=plots['plots'])


@app.route('/select_plot', methods=['POST'])
def select_plot():
    selected_plot_index = int(request.form['plot'])
    session['selected_plot'] = session['plots'][selected_plot_index]['plot']
    return redirect(url_for('thinking_chapters'))

@app.route('/thinking_chapters')
def thinking_chapters():
    description = "小説の章立てを考えています..."
    return render_template('thinking.html', next_url=url_for('generate_chapters'), description=description)

@app.route('/generate_chapters')
def generate_chapters():
    system_prompt = """
    あなたはプロの小説家です。
    以下のあらすじをもとに、小説の章立てを3章分、提案してください。各章のタイトルと簡単な内容をJSON形式で出力してください。
    出力フォーマット:
    {
     "chapters":[
        {
            "title": "第1章タイトル",
            "summary": "第1章の簡単な内容"
        },
        {
            "title": "第2章タイトル",
            "summary": "第2章の簡単な内容"
        },
        {
            "title": "第3章タイトル",
            "summary": "第3章の簡単な内容"
        }
      ]
    }
    """

    user_prompt = f"""
    あらすじ：{session['selected_plot']}
    """
    prompt = create_prompt(system_prompt, user_prompt)

    response = client.chat.completions.create(
        model=app.config['MODEL_NAME'],
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_prompt}
        ],
        response_format={ "type": "json_object" },
        temperature=app.config['TEMPERATURE'],
        max_tokens=app.config['MAX_TOKENS']
    )
    chapters_data = json.loads(response.choices[0].message.content)
    chapters = chapters_data['chapters']

    session['chapters'] = chapters

    return render_template('chapters.html', chapters=session['chapters'])


@app.route('/write_novel')
def write_novel():
    # 一時ファイルを作成(テキストファイル。PDF作成時に利用)
    temp_file = tempfile.NamedTemporaryFile(mode='w+', delete=False, encoding='utf-8', suffix=".txt")
    session['temp_file_path'] = temp_file.name  # パスのみを保存
    temp_file.close()

    return redirect(url_for('thinking_write_chapter', chapter_num=0))  # 最初の章から書き始める

@app.route('/thinking_write_chapter/<int:chapter_num>')
def thinking_write_chapter(chapter_num):
    description = f"小説の第{chapter_num + 1}章を執筆しています..."
    return render_template('thinking.html', next_url=url_for('write_chapter', chapter_num=chapter_num), description=description)

@app.route('/write_chapter/<int:chapter_num>')
def write_chapter(chapter_num):

    if chapter_num >= len(session['chapters']):
        # 全章書き終わったら中間結果表示へ
        return redirect(url_for('intermediate_result'))

    current_chapter = session['chapters'][chapter_num]
    system_prompt = """
    あなたはプロの小説家です。以下の情報と章の構成に基づき、指定された章の小説本文を1500字程度で執筆してください。
    """
    user_prompt = f"""
    小説のタイトル:{session['selected_title']}
    登場人物:{session['selected_characters']}
    これまでのあらすじ:{session['selected_plot']}
    章タイトル：{current_chapter['title']}
    章の内容：{current_chapter['summary']}
    """

    prompt = create_prompt(system_prompt, user_prompt)

    response = client.chat.completions.create(
        model=app.config['MODEL_NAME'],
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_prompt}
        ],
        temperature=app.config['TEMPERATURE'],
        max_tokens=app.config['MAX_TOKENS']
    )

    chapter_text = response.choices[0].message.content

    # 一時ファイルに追記
    with open(session['temp_file_path'], 'a', encoding='utf-8') as f:
        f.write(f"## {current_chapter['title']}\n\n{chapter_text}\n\n")

    # 次の章へ
    next_chapter_num = chapter_num + 1

    return render_template('writing.html', chapter_num=next_chapter_num, chapter_title=current_chapter['title'])

@app.route('/intermediate_result')
def intermediate_result():
    # 一時ファイルから小説のテキストを読み込む
    with open(session['temp_file_path'], 'r', encoding='utf-8') as f:
        novel_text = f.read()

    # 章タイトルを<h2>タグで囲む
    novel_text = novel_text.replace("## ", "<h2>").replace("\n\n", "</h2>\n\n<p>").replace("</h2>", "</p></h2>")

    return render_template('intermediate_result.html', novel_text=novel_text)

@app.route('/thinking_image') # 新しいルート
def thinking_image():
    description = "イラストを生成しています..."
    return render_template('thinking.html', next_url=url_for('result'), description=description)

@app.route('/result')
def result():
    # intermediate_resultを経由していない場合はトップページへリダイレクト
    if 'temp_file_path' not in session:
        flash('不正なアクセスです。')
        return redirect(url_for('index'))

    # OpenAI APIで画像を生成
    system_prompt_image = """
    あなたはプロのイラストレーターです。
    以下の小説の情報を元に、魅力的なシーンのイラストを1枚作成してください。
    """
    user_prompt_image = f"""
    小説のタイトル：{session['selected_title']}
    ジャンル:{session['genre']}
    登場人物：{session['selected_characters']}
    あらすじ：{session['selected_plot']}
    """
    prompt_image = create_prompt(system_prompt_image, user_prompt_image)

    try:
        response_image = client.images.generate(
            model="dall-e-3",
            prompt=prompt_image,
            size="1024x1024",
            quality="standard",
            n=1,
        )

        image_url = response_image.data[0].url

        # 画像を一時ファイルとして保存
        image_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
        os.system(f"curl '{image_url}' > {image_file.name}")  # curlで画像を保存
        session['image_file_path'] = image_file.name # 一時ファイルのパスを保存


    except Exception as e:
        flash(f"画像生成中にエラーが発生しました: {e}")
        return redirect(url_for('index'))  # エラー時はトップページへ

    # 現在の日時を取得し、ファイル名を生成(PDF用)
    now = datetime.datetime.now()
    filename = now.strftime("%Y%m%d%H%M%S") + ".pdf"
    session['filename'] = filename

     # log.txtにログを保存
    with open('log.txt', 'a', encoding='utf-8') as log_file:
        log_file.write(f"日時: {now.strftime('%Y-%m-%d %H:%M:%S')}\n")
        log_file.write(f"ニックネーム: {session.get('nickname', 'N/A')}\n")
        log_file.write(f"メールアドレス: {session.get('email', 'N/A')}\n")
        # 一時ファイルから小説のテキストを読み込む
        with open(session['temp_file_path'], 'r', encoding='utf-8') as f:
            novel_text = f.read()
        log_file.write(f"小説全文:\n{novel_text}\n")
        log_file.write("-" * 50 + "\n")


    return render_template('result.html', image_url=image_url, filename=filename)

@app.route('/generate_pdf')
def generate_pdf():
    # PDFオブジェクト作成
    pdf = PDF()

    # 表紙ページ
    pdf.add_cover_page()

    # 以降のページ (小説本文)
    pdf.add_font("IPAGothic", "", "ipag.ttf", uni=True)

    # 一時ファイルから小説のテキストを読み込む
    with open(session['temp_file_path'], 'r', encoding='utf-8') as f:
        novel_text = f.read()

    # 章ごとに分割
    chapters = novel_text.split("\n## ")

    for chapter in chapters:
        if "\n\n" in chapter:
            title, body = chapter.split("\n\n", 1)
            title = title.replace("## ", "")
        else:
            title = ""
            body = chapter

        pdf.add_page() # 各章の前に改ページ
        pdf.chapter_title(title)
        pdf.chapter_body(body)


    # 最終ページ
    pdf.add_last_page()

    # PDFを一時ファイルとして保存
    pdf_output = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf")
    pdf.output(pdf_output.name)
    session['pdf_file_path'] = pdf_output.name

    return send_file(session['pdf_file_path'], as_attachment=True, download_name=session['filename'])

@app.route('/thankyou')
def thankyou():
    # PDF一時ファイルを削除
    if 'pdf_file_path' in session:
        try:
            os.remove(session['pdf_file_path'])
        except FileNotFoundError:
            pass  # ファイルが存在しない場合は無視

    # テキスト一時ファイルを削除
    if 'temp_file_path' in session:
        try:
            os.remove(session['temp_file_path'])
        except FileNotFoundError:
            pass

    # 画像一時ファイルを削除
    if 'image_file_path' in session:
        try:
            os.remove(session['image_file_path'])
        except FileNotFoundError:
            pass

    # セッションデータをクリア
    session.clear()

    return render_template('thankyou.html')

if __name__ == '__main__':
    app.run(debug=True)